如何在 SQL Server 中不使用 OR 条件选择特定记录

Posted

技术标签:

【中文标题】如何在 SQL Server 中不使用 OR 条件选择特定记录【英文标题】:How to select a particular record without using OR condition in SQL Server 【发布时间】:2017-12-13 23:09:32 【问题描述】:
Item_Code   |Item_Description        |EAN Code      |Price   |Company_Code| Unit|
------------+------------------------+--------------+--------+------------+-----+
S-035-ED-TU |TCCA 35ml Everyday (100)|0000093507752 |4.220000|SKH         |EACH      
S-035-ED-TU |TCCA 35ml Everyday (100)|10000093507759|4.220000|SKH         |SHIPPER  
S-035-ED-TU |TCCA 35ml Everyday (100)|10000093507759|4.220000|SKH         |INNER   
S-050-PP-50P|TCCA 50ml Kids Peppa Pig|10000093545324|9.500000|SKH         |SHIPPER   

问题 - 对于某些项目代码,只有 1 个单元(发件人)可用,但对于某些项目代码,有 2 或 3 个单元代码(每个,发件人,INNER),如上例所示。

我想使用一个查询,如果表中的特定项目有多个 unit_code,则选择“每个”,否则选择“Shipper”或“EACH”或“INNER”,无论可用。

谢谢 图沙尔

【问题讨论】:

你为什么反对使用OR 需要知道您使用的是哪个数据库。 “sql”是一种语言标准,但每个数据库都有不同的语法实现(例如:mysql、SQL Server、Oracle ...?) 我使用的是 SQL Server 2014 @user9096211 然后将 SQL Server 标记添加到您的问题中。 【参考方案1】:

对于支持“窗口函数”的数据库,这可能会满足您的需求:

SELECT
      d.*
FROM (
      SELECT
            t.*
          , ROW_NUMBER() OVER (PARTITION BY Item_Code
            ORDER BY CASE WHEN Unit = 'EACH' THEN 1 
                          WHEN unint = 'SHIPPER' THEN 2 ELSE 3 END) AS unit_pref
      FROM yourtable t
      ) d
WHERE d.unit_pref = 1

nb:MySQL(目前为 5.7)不(还)支持“窗口函数”,但会在版本 8 中支持

【讨论】:

【参考方案2】:

这是 SQL Server 中的 2 个解决方案。我认为第二个更好

CREATE TABLE #test (
    item_code NVARCHAR(1000),
    item_description NVARCHAR(1000),
    ean_code NVARCHAR(1000),
    price NVARCHAR(1000),
    campany_code NVARCHAR(1000),
    unit NVARCHAR(1000),
    )

INSERT INTO #test (
    item_code,
    item_description,
    ean_code,
    price,
    campany_code,
    unit
    )
VALUES (
    'S-035-ED-TU',
    'TCCA 35ml Everyday (100)',
    '0000093507752',
    '4.220000',
    'SKH',
    'EACH'
    ),
    (
    'S-035-ED-TU',
    'TCCA 35ml Everyday (100)',
    '0000093507752',
    '4.220000',
    'SKH',
    'SHIPPER'
    ),
    (
    'S-035-ED-TU',
    'TCCA 35ml Everyday (100)',
    '0000093507752',
    '4.220000',
    'SKH',
    'INNER'
    ),
    (
    'S-050-PP-50P',
    'TCCA 50ml Kids Peppa Pig',
    '10000093545324',
    '9.500000',
    'SKH',
    'SHIPPER'
    )

--Get all records just to see
SELECT *
FROM #test

--METHOD 1: One way you could do it
SELECT *
FROM #test t
WHERE unit = CASE 
        WHEN (
                SELECT count(*)
                FROM #test t2
                WHERE t.item_code = t2.item_code
                ) > 1
            THEN 'EACH'
        ELSE unit
        END

--METHOD 2: Maybe a better way to do it using a temp table
SELECT t.item_code,
    count(*) RecordsPerGroup
INTO #itemCodeCount
FROM #test t
GROUP BY item_code

SELECT t.*
FROM #test t
LEFT JOIN #itemCodeCount icc
    ON t.item_code = icc.item_code
WHERE t.unit = CASE 
        WHEN icc.RecordsPerGroup > 1
            THEN 'EACH'
        ELSE t.unit
        END

DROP TABLE #test

DROP TABLE #itemCodeCount

【讨论】:

嗨,奥斯汀,感谢您的回复。有 1 个关于 t2 的问题,您已在 where 子句中将测试表重命名为 t2 对吗?或者它是从哪里来的? 它只是一个选择内部的内部选择,所以你必须给表一个别名,即tt2【参考方案3】:

试试这个:

    create table #tmp(Item_Code VARCHAR(50),EAN_Code VARCHAR(100),Unit VARCHAR(10))



    insert into #tmp VALUES('S-035-ED-TU','10000093507759','SHIPPER')
    insert into #tmp VALUES('S-035-ED-TU','10000093507759','INNER')
    insert into #tmp VALUES('S-035-ED-TU','0000093507752','EACH')

    insert into #tmp VALUES('S-050-PP-50P','10000093545324','SHIPPER')


    select Item_Code 
    into #tmpMultiUnit
    from #tmp 
    Group by Item_Code
    Having Count(Unit)>1

    SELECT t.* from #tmp t
    LEFT JOIN #tmpMultiUnit tm on t.Item_Code=tm.Item_Code
    WHERE tm.Item_Code IS NULL OR t.Unit='EACH'

    Drop table #tmp

    DRop table #tmpMultiUnit

【讨论】:

【参考方案4】:

我知道这已经晚了三 (3) 年,但以防万一有人有同样的问题,这是我的贡献。

使用您插图中的列,我需要创建表格:

CREATE TABLE #tmp (
    Item_Code NVARCHAR(100),
    Item_Description NVARCHAR(100),
    EAN_Code VARCHAR(100),
    Price DECIMAL(22,6),
    Company_Code NVARCHAR(50),
    Unit VARCHAR(10)
)

INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'EACH')
INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'SHIPPER')
INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'INNER')
insert into #tmp VALUES('S-050-PP-50P','TCCA 50ml Kids Peppa Pig', '10000093545324', 9.500000, 'SKH', 'SHIPPER')

那么,查询可以这样表示:

SELECT t.Item_Code, t.Item_Description, t.EAN_Code, t.Price, t.Company_Code, 
        CASE WHEN uom.Count > 1 THEN 'EACH' ELSE t.Unit END AS Unit,
        t.Unit AS [(OriginalUnit)]
FROM #tmp t
    INNER JOIN (SELECT COUNT(1) AS Count, Item_Code FROM #tmp GROUP BY Item_Code) uom ON t.Item_Code = uom.Item_Code

结果:

现在,当需要显示与 EACH 等效的新计量单位时,此查询将不会是通用的,因为查询已被硬编码为在遇到项目代码的多个单位时显示 EACH。从众多选择单位必须有依据。我冒昧地修改了表格,添加了Conversion 列作为指标。

CREATE TABLE #tmp (
    Item_Code NVARCHAR(100),
    Item_Description NVARCHAR(100),
    EAN_Code VARCHAR(100),
    Price DECIMAL(22,6),
    Company_Code NVARCHAR(50),
    Unit VARCHAR(10),
    Conversion float /* Added to automatically select which ever has the lowest conversion */
)

INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'EACH', 1)    
INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'INNER', 4)
INSERT INTO #tmp VALUES('S-035-ED-TU','TCCA 35ml Everyday (100)', '10000093507759', 4.220000, 'SKH' ,'SHIPPER', 24)
INSERT INTO #tmp VALUES('S-050-PP-50P','TCCA 50ml Kids Peppa Pig', '10000093545324', 9.500000, 'SKH', 'SHIPPER', 1)

那么我们只需找到转换率最低的单位:

SELECT t.Item_Code, t.Item_Description, t.EAN_Code, t.Price, t.Company_Code, 
        CASE WHEN uom.NumUnit > 1 THEN uom.Unit ELSE t.Unit END AS Unit,
        t.Unit AS [(OriginalUnit)]
FROM #tmp t
    INNER JOIN (SELECT t2.NumUnit, t1.Item_Code, t1.Unit 
                FROM #tmp t1
                    INNER JOIN (SELECT COUNT(1) AS NumUnit, Item_Code, MIN(Conversion) AS Conversion
                                FROM #tmp       
                                GROUP BY Item_Code) t2 ON t1.Item_Code = t2.Item_Code AND t1.Conversion = t2.Conversion) uom ON t.Item_Code = uom.Item_Code

产生相同的结果,但 EACH 没有硬编码:

要验证连接的子查询是否选择正确,请从主查询中提取并运行:

SELECT t2.NumUnit, t1.Item_Code, t1.Unit 
FROM #tmp t1
    INNER JOIN (SELECT COUNT(1) AS NumUnit, Item_Code, MIN(Conversion) AS Conversion
                FROM #tmp       
                GROUP BY Item_Code) t2 ON t1.Item_Code = t2.Item_Code AND t1.Conversion = t2.Conversion

结果:

【讨论】:

以上是关于如何在 SQL Server 中不使用 OR 条件选择特定记录的主要内容,如果未能解决你的问题,请参考以下文章

如何组合多行数据,直到下一行值在 SQL Server 中不为空

如何从 SQL Server 中不同行的列中取值?

如何在此 Access-SQL server-Visual Basic 6 (ADO) 表单中不包含重复元素(主详细信息)

如何在 SQL Server 中的 OR 条件中确定优先级

函数在 sql server 上的 CHECK Constraint 中不起作用

本地主机在 sql server 2005 中不起作用