SQL 服务器查询与 Oracle 查询相同吗?

Is the SQL Server query same as Oracle query?

由于 SQL 服务器不允许比较两列(例如,where (store_nbr, item_id)),我很难比较查询,尤其是当表有大量数据。

我有 3 张桌子

我有以下 Oracle 查询

FORCE_TAGS_SQL = """UPDATE /*+ dynamic_sampling(0) index(store_item store_item_pk) */ store_item SET user_bit_5 = '1'
                     WHERE (store_nbr, item_id) in (SELECT /*+ dynamic_sampling(0) index(tag_demand tag_demand_ix1) */ d.store_nbr, d.item_id
                                                      FROM store s, tag_demand d
                                                     WHERE s.division_id = 'XYZ'
                                                       AND d.store_nbr = s.store_nbr
                                                       AND d.print_dt = TRUNC(TO_DATE('2022-04-13', 'YYYY-MM-DD')))
                       AND user_bit_5 = '0'
                 """

以下是转换后的SQL服务器查询

FORCE_TAGS_SQL = """UPDATE STORE_ITEM SET user_bit_5 = '1'
                     WHERE (store_nbr) in (SELECT d.store_nbr
                                                      FROM STORE s, tag_demand d
                                                     WHERE s.division_id = 'XYZ'
                                                       AND d.store_nbr = s.store_nbr
                                                       AND d.print_dt = CONVERT(DATETIME, CONVERT(DATE, '2022-04-13')))
                       AND (item_id) in (SELECT  d.item_id
                                                      FROM STORE s, tag_demand d
                                                     WHERE s.division_id = 'XYZ'
                                                       AND d.store_nbr = s.store_nbr
                                                       AND d.print_dt = CONVERT(DATETIME, CONVERT(DATE, '2022-04-13')))
                      AND user_bit_5 = '0'
                 """

SQL 服务器查询与 Oracle 查询相同吗?

更新:

UPDATE  store_item SET user_bit_5 = '1'
FROM    store_item item INNER JOIN tag_demand d
ON      d.store_nbr = item.store_nbr AND d.item_id = item.item_id
WHERE   d.store_nbr in ((SELECT s.store_nbr FROM STORE s WHERE s.division_id = 'XYZ')) AND d.print_dt = CONVERT(DATETIME, CONVERT(DATE, '2022-04-13'))

更新#2:

 FORCE_TAGS_SQL = """UPDATE STORE_ITEM SET user_bit_5 = '1'
                                FROM STORE_ITEM
                                inner join (
                                    SELECT d.store_nbr, d.item_id
                                    FROM store s, tag_demand d
                                    WHERE d.store_nbr = s.store_nbr AND s.division_id = 'XYZ' AND d.print_dt = CONVERT(DATETIME, CONVERT(DATE, '2022-04-13'))
                                ) tagdemand
                                on tagdemand.store_nbr = STORE_ITEM.store_nbr
                                AND tagdemand.item_id = STORE_ITEM.item_id
                                where user_bit_5 = '0'
                    """

更新#3

FORCE_TAGS_SQL = """UPDATE STORE_ITEM SET user_bit_5 = '1'
                            FROM STORE_ITEM
                            INNER JOIN tag_demand
                                ON 
                                    STORE_ITEM.item_id = tag_demand.item_id
                                AND STORE_ITEM.store_nbr = tag_demand.store_nbr
                                AND tag_demand.print_dt = '2022-04-11'
                                AND tag_demand.STORE_NBR in (SELECT store_nbr FROM store WHERE division_id = 'XYZ')
                            where user_bit_5 = '0'
                """

如果您想要相同的逻辑,可以使用 CONCAT()。我无法告诉您这会使查询速度减慢多少。

WHERE (CONCAT(store_nbr, item_id)) in
(SELECT CONCAT(d.store_nbr, d.item_id)
FROM...)

区别在于您的 SQL 服务器版本更加自由。在 oracle 版本将接受 (A,1) 和 (B,2) 的情况下,即使这些组合不存在,您的 SQL 服务器版本也将接受 (A,2) 和 (B,1)在 sub-query.
一个简单的测试是检查从同一数据返回的行数。如果SQL服务器版本returns多行就知道有问题了。

您可能应该重构为 exists 而不是尝试在列表中使用子选择,因为这很可能会给您不同的结果。

...
WHERE EXISTS (SELECT *
              FROM ...
              JOIN ...
              WHERE store.store_nbr = store_item.store_nbr
                AND tag_demand.item_id = store_item.item_id
                AND tag_demand.print_dt = ...)

顺便说一句,使用 JOIN 而不是 CARTESIAN PRODUCT 和 RESTRICTION 的组合(在 WHERE 子句“à la” Oracle 中错误加入!)。这是您用纯 SQL ISO 标准 1992 重写的查询:

UPDATE store_item 
SET    user_bit_5 = '1'
WHERE  (store_nbr, item_id) in (SELECT d.store_nbr, d.item_id
                                FROM   store s
                                       JOIN tag_demand d
                                          ON d.store_nbr = s.store_nbr
                                WHERE  s.division_id = 'XYZ'
                                       AND d.print_dt = '2022-04-13')
       AND user_bit_5 = '0';

一种解决方案是使用 相关 IN :

UPDATE T
SET    user_bit_5 = '1'
FROM   store_item  AS T
WHERE  (store_nbr) in (SELECT d.store_nbr
                       FROM   store s
                              JOIN tag_demand d
                                 ON d.store_nbr = s.store_nbr
                       WHERE  s.division_id = 'XYZ'
                              AND d.print_dt = '2022-04-13'
                              AND d.item_id = T.item_id)
       AND user_bit_5 = '0';

另一个是在UPDATE中使用JOIN:

UPDATE T
SET    user_bit_5 = '1'
FROM   store_item AS T
       JOIN tag_demand d
          ON T.store_nbr = d.store_nbr
             AND T.item_id = d. item_id
       JOIN store s
          ON d.store_nbr = s.store_nbr
WHERE  s.division_id = 'XYZ'
       AND d.print_dt = '2022-04-13'
       AND user_bit_5 = '0';

我的首选解决方案是使用具有双重相关性的 EXISTS:

UPDATE store_item 
SET    user_bit_5 = '1'
WHERE  EXISTS(SELECT 0/0
              FROM   store s
                     JOIN tag_demand d
                        ON d.store_nbr = s.store_nbr
              WHERE  s.division_id = 'XYZ'
                     AND d.print_dt = '2022-04-13'
                     AND store_itme.store_nbr = d.store_nbr
                     AND store_itme.item_id =  d.item_id)
       AND user_bit_5 = '0'

有些解决方案可以使用 INTERSECT 运算符,但需要了解 table 说明,尤其是 PK

具有 CONCAT 函数或类似...的所有其他解决方案将在结果集中产生误报行值。