为什么IN运算符显示错误的结果?

时间:2013-05-27 10:19:31

标签: sql sql-server-2008 tsql sql-server-2005

我有这个表BarCode,当我在这样的查询中执行

SELECT Barcode 
FROM BarcodeTable 
WHERE BarCode IN 
            (
                '53-3-1',
                '51-1-1',
                '51-2-1',
                '50-10-1',
                '50-8-1',
                '51-4-1',
                '50-1-1'
            )

为什么我会

53-3-1
50-1-1
50-8-1
50-10-1
51-1-1
51-2-1
51-4-1

而不是????

53-3-1
51-1-1
51-2-1
50-10-1
50-8-1
51-4-1
50-1-1

为什么SQL会改变条形码的顺序?由于SQL对它们进行排序(单独使用)的方式导致sp_executesql执行的动态查询中的错误依赖于我发送输入的顺序。为什么SQL会自行更改输入顺序?

51-4-1

4 个答案:

答案 0 :(得分:3)

除非您按语句指定订单,否则不应依赖输出中的特定订单。您必须提供ORDER BY才能获得预期效果。

答案 1 :(得分:3)

IN并不意味着对最终结果的任何排序:

这个SQL:

... WHERE x IN (1, 2, 3)

应该产生与此相同的结果:

... WHERE x IN (3, 2, 1)

IN子句只过滤行,基本上,对于你能想到的每行,只要问“这行应该是结果集的一部分吗?”。

要获得特定的排序,您必须在语句中添加ORDER BY子句。

要获取特定订单,您可以使用内联表:

SELECT Barcode
FROM BarcodeTable
    inner join (values
        ('*53-3-1*',  1),
        ('*51-1-1*',  2),
        ('*51-2-1*',  3),
        ('*50-10-1*', 4),
        ('*50-8-1*',  5),
        ('*51-4-1*',  6),
        ('*50-1-1*',  7)) as DummyTable (value, sortorder)
    on BarCode = value
order by
    sortorder

这将按DummyTable的sortorder字段排序。

您不能欺骗SQL Server使用IN子句本身进行排序, 以某种形式添加ORDER BY

您还可以使用CASE WHEN ...表达式根据条形码生成排序顺序值:

SELECT Barcode
FROM BarcodeTable
WHERE BarCode IN ('*53-3-1*', '*51-1-1*', '*51-2-1*', '*50-10-1*', '*50-8-1*', '*51-4-1*', '*50-1-1*')
ORDER BY
    CASE BarCode
        WHEN '*53-3-1*'  THEN 1
        WHEN '*51-1-1*'  THEN 2
        WHEN '*51-2-1*'  THEN 3
        WHEN '*50-10-1*' THEN 4
        WHEN '*50-8-1*'  THEN 5
        WHEN '*51-4-1*'  THEN 6
        WHEN '*50-1-1*'  THEN 7
    END

正如Lieven的评论所暗示的那样,使用WITH子句在SQL Server 2005上有另一种选择:

WITH DummyTable (value, sortorder) AS (
    SELECT '*53-3-1*' AS value,  1 AS sortorder
    UNION ALL
    SELECT '*51-1-1*',  2
    UNION ALL
    SELECT '*51-2-1*',  3
    UNION ALL
    SELECT '*50-10-1*', 4
    UNION ALL
    SELECT '*50-8-1*',  5
    UNION ALL
    SELECT '*51-4-1*',  6
    UNION ALL
    SELECT '*50-1-1*',  7
)
SELECT Barcode
FROM BarcodeTable
    inner join DummyTable
    on BarCode = value
order by
    sortorder

(注意,我不是WITH使用方面的专家,上面只是我一起入侵的东西,但似乎有效)

答案 2 :(得分:1)

要按照您的预期进行查询,您需要添加ORDER BY,否则排序将不可靠。这样的东西应该可以工作但是根据你的条形码数量,一旦返回结果,最终可能更容易在代码中正确地订购;

SELECT Barcode 
FROM BarcodeTable 
WHERE BarCode IN ('*53-3-1*','*51-1-1*','*51-2-1*','*50-10-1*',
                  '*50-8-1*','*51-4-1*','*50-1-1*')
ORDER BY CASE BarCode WHEN '*53-3-1*'  THEN 1
                      WHEN '*51-1-1*'  THEN 2
                      WHEN '*51-2-1*'  THEN 3
                      WHEN '*50-10-1*' THEN 4
                      WHEN '*50-8-1*'  THEN 5
                      WHEN '*51-4-1*'  THEN 6
                      WHEN '*50-1-1*'  THEN 7
                      END

答案 3 :(得分:0)

尝试以下代码

SELECT Barcode ,CASE Col_Order WHEN '53-3-1'  THEN 1
                      WHEN '51-1-1'  THEN 2
                      WHEN '51-2-1'  THEN 3
                      WHEN '50-10-1' THEN 4
                      WHEN '50-8-1'  THEN 5
                      WHEN '51-4-1'  THEN 6
                      WHEN '50-1-1'  THEN 7 
                      END     
FROM BarcodeTable 
WHERE BarCode IN 
            (
                '53-3-1',
                '51-1-1',
                '51-2-1',
                '50-10-1',
                '50-8-1',
                '51-4-1',
                '50-1-1'
            )    
ORDER BY Col_Order