多个记录集问题

时间:2012-02-17 12:38:53

标签: sql sql-server vba ado

我有以下SQL脚本,它是使用ADO针对SQL Server 2000数据库从Excel VBA运行的。

我遇到的问题是,虽然脚本中只有一个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

2 个答案:

答案 0 :(得分:0)

我会在临时表的末尾添加一个同位素列(虚拟列),这样当您看到三个记录集时,您可以询问列名称以查看它们来自何处。当您从配置文件中获取SQL并直接在SSMS中运行时会发生什么?你只得到一个结果集吗?

答案 1 :(得分:0)

我终于找到了这个问题,并认为我会报告回来。问题在于脚本中的两个聚合函数中的NULL值。这种情况偶尔发生的原因是因为数据不断变化。

尽管SQL Server“静默地”处理问题,但它确实会产生警告,ADO将其视为记录集,尽管在我的情况下(可能是每种情况)这些记录集都已关闭,因此无法实际查看它们包含的内容或产生它们的内容。 / p>

我没有用ISNULL()逻辑重写SQL脚本,而是选择仅包括

SET ANSI_WARNINGS OFF 
脚本顶部的

语句。这可以防止报告警告,因此ADO不会产生这些额外的不需要的记录集。

失望我没有早点发现这一点,但至少我学会了一些新东西。 :)