2012-02-17 6 views
0

SQL Server 2000データベースに対してADOを使用してExcel VBAから実行される以下のSQLスクリプトがあります。複数のレコードセット問題

問題は、スクリプトにSELECT文が1つしかありませんが、.Openメソッドを実行すると3つのレコードセットを受け取ることがあることです。私はときどき、時には言いますが、他の「並列」データベースでは、レコードセットを1つだけ戻します。

私は.NextRecordset()メソッドなどについて知っていますが、私はなぜ3つのレコードセットを取得するのか理解しようとしています。私はまもなくSQLトレースを実行して、それがどんなアイディアを投げ出すかどうかを見ていきますが、いつものように、どんな助けやアドバイスも大歓迎です。

SET NOCOUNT ON 
DECLARE @RunDate VARCHAR(8) 

SET @RunDate = CONVERT(VARCHAR(8), DATEADD(d, -1 * 1, GETDATE()), 112) 

IF OBJECT_ID('tempdb..#ActiveOrders') IS NOT NULL DROP TABLE #ActiveOrders 
IF OBJECT_ID('tempdb..#ApplicableOrders') IS NOT NULL DROP TABLE #ApplicableOrders 
IF OBJECT_ID('tempdb..#FilterOut') IS NOT NULL DROP TABLE #FilterOut 

/*Temp table created as it has a self-join in the below query */ 
CREATE TABLE #ActiveOrders(
    order_id VARCHAR(30) 
    , instrument_id VARCHAR(30) 
    , side CHAR(1) 
    ) 

CREATE INDEX idx_ActiveOrders_orderId ON #ActiveOrders(order_id) 

/*Build dataset of all orders which have had activity on the run date or are in an Open status. Ignoring Program Trades.*/ 
INSERT INTO #ActiveOrders 
SELECT o1.order_id COLLATE Latin1_General_CI_AS 
     , o1.instrument_id 
     , o1.side 
FROM orders o1 
INNER JOIN desk d1 ON d1.desk_id = o1.investment_desk 
INNER JOIN (SELECT o0.order_id 
      FROM orders o0 
      WHERE ((LEFT(o0.added_datetime, 8) = @RunDate 
        OR LEFT(o0.approved_datetime, 8) = @RunDate) 
        OR (LEFT(o0.added_datetime, 8) <= @RunDate 
        AND o0.summary_status IN (1, 2, 3, 5, 8, 9))) /*Approved, Assigned, Acknowledged, Working, Partial, WorkingPartial*/ 
      UNION 
      (SELECT r0.order_id 
      FROM releases r0 
      WHERE LEFT(r0.added_datetime, 8) = @RunDate) 
      UNION 
      (SELECT e0.order_id 
      FROM executions e0 
      WHERE LEFT(e0.execution_datetime, 8) = @RunDate 
        OR LEFT(e0.allocated_datetime, 8) = @RunDate) 
      ) t1 ON o1.order_id = t1.order_id 
WHERE d1.location_id = 'LDEQ'  
     AND o1.summary_status <> 4 
     AND o1.list_id IS NULL /*Ignore program trades*/ 

/*This is now the actual dataset we are interested in. 
This is everything which could be a contender for aggregation.*/ 
CREATE TABLE #ApplicableOrders(
    order_id VARCHAR(30) 
    , instrument_id VARCHAR(30) 
    , side CHAR(1) 
    , approved_datetime DATETIME 
    , acknowledged_datetime DATETIME 
    , last_allocation_datetime DATETIME 
    , latest_status INT 
    , merged_orders VARCHAR(500) 
    , dealer VARCHAR(100) 
    , manager VARCHAR(100) 
    , limit_price FLOAT 
    , original_qty FLOAT 
    , executed_qty FLOAT 
    , trader_instruction TEXT 
    , dealer_note TEXT 
    ) 

CREATE INDEX idx_ApplicableOrders_orderId ON #ApplicableOrders(order_id) 
CREATE INDEX idx_ApplicableOrders_lastAllocation ON #ApplicableOrders(last_allocation_datetime) 
CREATE INDEX idx_ApplicableOrders_approved ON #ApplicableOrders(approved_datetime) 

/*All orders from #ActiveOrders where there are two or more orders which are for the same instrument and in the same direction.*/ 
INSERT INTO #ApplicableOrders 
SELECT o.order_id 
     , o.instrument_id 
     , o.side 
     , dbo.mglz_datetime(o.approved_datetime) 
     , dbo.mglz_datetime(o.ack_datetime) 
     , MAX(dbo.mglz_datetime(e.allocated_datetime)) "Last Allocation DateTime" 
     , o.summary_status 
     , o.merged_orders 
     , o.ack_id 
     , o.approver_id 
     , o.limit_price 
     , o.original_qty 
     , o.executed_qty_at 
     , CONVERT(VARCHAR(900), o.trader_instruction) 
     , CONVERT(VARCHAR(900), o.dealer_note) 
FROM orders o 
     INNER JOIN #ActiveOrders t ON o.order_id = t.order_id COLLATE Latin1_General_CI_AS 
     INNER JOIN #ActiveOrders s ON s.order_id <> o.order_id COLLATE Latin1_General_CI_AS 
             AND s.instrument_id = o.instrument_id COLLATE Latin1_General_CI_AS 
             AND s.side = o.side COLLATE Latin1_General_CI_AS 
     LEFT JOIN executions e ON e.order_id = o.order_id 
GROUP BY o.order_id 
     , o.instrument_id 
     , o.side 
     , o.approved_datetime 
     , o.ack_datetime 
     , o.summary_status 
     , o.merged_orders 
     , o.ack_id 
     , o.approver_id 
     , o.limit_price 
     , o.original_qty 
     , o.executed_qty_at 
     , CONVERT(VARCHAR(900), o.trader_instruction) 
     , CONVERT(VARCHAR(900), o.dealer_note) 

/*Filter out any orders where Order2.Approved_Date > Order1.Last_Release_Date AND Order1.Is_Complete 
Order1 is defined as the order which was approved first.*/ 
SELECT t1.* 
INTO #FilterOut 
FROM #ApplicableOrders t1 
WHERE EXISTS (SELECT 1 
       FROM 
        (SELECT order2.order_id 
        FROM (SELECT b.order_id 
            , b.instrument_id 
            , b.side 
            , b.approved_datetime 
            , b.last_allocation_datetime 
            , b.latest_status 
            , b.executed_qty 
            , b.original_qty 
          FROM #ApplicableOrders b 
          WHERE b.approved_datetime = (SELECT MIN(b1.approved_datetime) FirstApproval 
                 FROM #ApplicableOrders b1 
                 WHERE b1.instrument_id = b.instrument_id 
                  AND b1.side = b.side) 
         ) order1 
        INNER JOIN 
         (SELECT c.order_id 
           , c.instrument_id 
           , c.side 
           , c.approved_datetime 
          FROM #ApplicableOrders c 
          WHERE c.approved_datetime > (SELECT MIN(c1.approved_datetime) FirstApproval 
                 FROM #ApplicableOrders c1 
                 WHERE c1.instrument_id = c.instrument_id 
                  AND c1.side = c.side) 
         ) order2 
        ON order1.instrument_id = order2.instrument_id 
         AND order1.side = order2.side 
         AND order2.approved_datetime > order1.last_allocation_datetime 
         AND (order1.latest_status = 6 OR order1.executed_qty = order1.original_qty)) filter1 
       WHERE t1.order_id = filter1.order_id) 

/*Filter out any orders where Order2.Acknowledged_Date > Order1.Last_Allocation_Date.*/ 
INSERT INTO #FilterOut 
    SELECT t1.* 
    FROM #ApplicableOrders t1 
    WHERE EXISTS (SELECT 1 
        FROM 
         (SELECT order2.order_id 
         FROM (SELECT b.order_id 
            , b.instrument_id 
            , b.side 
            , b.approved_datetime 
            , b.last_allocation_datetime 
          FROM #ApplicableOrders b 
          WHERE b.approved_datetime = (SELECT MIN(b1.approved_datetime) FirstApproval 
                 FROM #ApplicableOrders b1 
                 WHERE b1.instrument_id = b.instrument_id 
                  AND b1.side = b.side) 
          ) order1 
         INNER JOIN 
          (SELECT c.order_id 
            , c.instrument_id 
            , c.side 
            , c.approved_datetime 
            , c.acknowledged_datetime 
           FROM #ApplicableOrders c 
           WHERE c.approved_datetime > (SELECT MIN(c1.approved_datetime) FirstApproval 
                  FROM #ApplicableOrders c1 
                  WHERE c1.instrument_id = c.instrument_id 
                   AND c1.side = c.side) 
          ) order2 
         ON order1.instrument_id = order2.instrument_id 
          AND order1.side = order2.side 
          AND order2.acknowledged_datetime > order1.last_allocation_datetime) filter2 
        WHERE t1.order_id = filter2.order_id) 
    AND NOT EXISTS (SELECT 1 
        FROM #FilterOut a1 
        WHERE a1.order_id = t1.order_id) 

/*Filter any 'single' orders. I.e. all 'matching' orders have been excluded so the instrument/direction combination is not applicable for Aggregation.*/ 
INSERT INTO #FilterOut 
    SELECT t1.* 
    FROM #ApplicableOrders t1 INNER JOIN (SELECT DISTINCT t.instrument_id 
                  , t.side 
              FROM #ApplicableOrders t 
              INNER JOIN #FilterOut a ON t.instrument_id = a.instrument_id 
                       AND t.side = a.side 
              GROUP BY t.instrument_id 
                , t.side 
              HAVING COUNT(t.instrument_id) > 1) t2 ON t1.instrument_id = t2.instrument_id 
                         AND t1.side = t2.side 
    WHERE NOT EXISTS (SELECT 1 
         FROM #FilterOut a1 
         WHERE a1.order_id = t1.order_id) 

/*Final Report*/ 
/*A list of all orders where aggregation could have possibly occurred but didn't.*/ 
SELECT t1.order_id "Order ID" 
     , i.name "Name" 
     , t1.side "B/S" 
     , userDealer.short_name "Dlr" 
     , userManager.short_name "FM" 
     , t1.limit_price "Limit" 
     , t1.approved_datetime "Order Approved" 
     , t1.acknowledged_datetime "Order Acknowledged" 
     , t1.last_allocation_datetime "Last Execution" 
     , t1.merged_orders "Merged Orders" 
     , m.description "Status" 
     , t1.dealer_note "Dealer Note" 
     , t1.trader_instruction "Trader Instruction" 
FROM #ApplicableOrders t1 
    INNER JOIN instrument i ON t1.instrument_id = i.instrument_id COLLATE Latin1_General_CI_AS 
    INNER JOIN mnemonics m ON t1.latest_status = m.value AND m.attribute = 'order_summary_status' 
    LEFT JOIN users userDealer ON userDealer.user_id = t1.dealer COLLATE Latin1_General_CI_AS 
    LEFT JOIN users userManager ON userManager.user_id = t1.manager COLLATE Latin1_General_CI_AS 
WHERE NOT EXISTS (SELECT 1 
        FROM #FilterOut t2 
        WHERE t1.order_id = t2.order_id) 
ORDER BY t1.name 
     , t1.side 
     , t1.approved_datetime 

IF OBJECT_ID('tempdb..#ActiveOrders') IS NOT NULL DROP TABLE #ActiveOrders 
IF OBJECT_ID('tempdb..#ApplicableOrders') IS NOT NULL DROP TABLE #ApplicableOrders 
IF OBJECT_ID('tempdb..#FilterOut') IS NOT NULL DROP TABLE #FilterOut 
+0

私は3つのレコードセットを受け取ったときに、最初の2つは閉じた状態になり、返されるレコードがないことを示します。 – markblandford

+0

SQL Traceでデッドエンドを打ってSQLを演奏した後、問題は2つのWHERE EXISTS(SELECT 1 ... – markblandford

答えて

0

私はついにこの問題を発見し、私が報告すると思いました。この問題は、スクリプト内の2つの集計関数でNULL値が原因で発生していました。これはたまにしか発生しなかったのは、データが絶えず変化したためです。

SQL Serverは問題を「静かに」処理しますが、ADOがレコードセットと見なす警告を生成しますが、私の場合(すべての場合があります)、これらのレコードセットは閉じられています。

代わりの再書き込みISNULL()ロジックとSQLスクリプトは、私は単にスクリプトの先頭に

SET ANSI_WARNINGS OFF 

文を含めることを選択した

。これにより、警告が報告されないようにするため、ADOは不要な追加のレコードセットを生成しません。

私はこれを以前は見つけていませんでしたが、少なくとも私は新しいことを学びました。 :)

+0

あなた自身の答えを受け入れてください。 –

0

次の3つのレコードセットを参照するときに、彼らはから来ている場所を確認するために、列名を調べることができるように私はあなたの一時テーブルの最後に同位体カラム(ダミー列)を追加します。そして、プロファイルからSQLを取り出してSSMSで直接実行するとどうなりますか?結果セットは1つだけですか?

+0

ありがとうございましたが、返された3つのレコードセットのうちの2つSSMSで実行されると、私は1つのレコードセットを返すように見えますが、問題はWHEREであると確信していますEXISTSステートメント(私は2つのSELECTステートメントを持っているので)残念ながら問題は解決していないので、私はそれを証明できません。どちらかといえば、結果を投稿します。 – markblandford

関連する問題