2012-02-17 1 views
0

У меня есть следующий SQL-скрипт, который запускается из Excel VBA с использованием ADO для базы данных SQL Server 2000.Проблема с несколькими наборами записей

Проблема заключается в том, что хотя в скрипте есть только одна инструкция SELECT, я иногда получаю три набора записей при выполнении метода .Open. Я говорю иногда, как по случаю, так и по другим «параллельным» базам данных, я получаю только один набор записей.

Я знаю все о методе .NextRecordset() и т. Д., Но я пытаюсь понять, почему я возвращаю три набора записей несколько раз, а иногда я получаю только один. Я вскоре собираюсь запустить 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 набора записей, первые два находятся в закрытом состоянии, указывая на то, что записей не было. – markblandford

+0

После попадания в тупик с помощью SQL Trace и игры с SQL, я думаю, что проблема, похоже, связана с двумя WHERE EXISTS (SELECT 1 ... – markblandford

ответ

0

Я, наконец, нашел проблему и подумал, что буду отчитываться. Проблема заключалась в значениях NULL в двух из функций агрегации в скрипте. Причина, по которой это случалось только изредка, заключается в том, что данные постоянно менялись.

Несмотря на то, что SQL Server обрабатывает проблему «молча», она создает предупреждения, которые ADO видит в качестве наборов записей, хотя в моем случае (может быть, каждый случай) эти наборы записей закрыты и поэтому невозможно реально увидеть, что они содержат или что их создало.

Вместо переписывания сценария SQL с ISNULL() логики, я решил просто включить заявление

SET ANSI_WARNINGS OFF 

в верхней части сценария. Это предотвращает сообщение предупреждений и, таким образом, ADO не создает эти дополнительные нежелательные записи.

Разочарованный Я не заметил этого раньше, но, по крайней мере, я узнал что-то новое. :)

+0

Good Решение. Примите свой ответ. –

0

Я хотел бы добавить столбец изотопа (фиктивный столбец) до конца ваших временных таблиц, так что, когда вы видите три набора записей можно опрашивать имена столбцов, чтобы видеть, куда они приходят. И что происходит, когда вы берете SQL из профиля и запускаете непосредственно в SSMS? Вы получаете только один набор результатов?

+0

Благодарим вас за предложение, но два из трех возвращенных записей указаны в закрытое состояние, так что я не могу ничего с ними сделать, поэтому я изо всех сил пытаюсь определить, что их вызывает. Когда я запускаю SSMS, я только возвращаю один набор записей. Я убежден, что проблема связана с WHERE EXISTS (поскольку у меня есть два из них [и они являются операторами SELECT]), но, к сожалению, проблема разрешилась сама по себе, поэтому я не могу это доказать. Как только я знаю в любом случае, я опубликую свои результаты. – markblandford