如何在 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 对吗?或者它是从哪里来的? 它只是一个选择内部的内部选择,所以你必须给表一个别名,即t
和t2
【参考方案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 中不为空
如何在此 Access-SQL server-Visual Basic 6 (ADO) 表单中不包含重复元素(主详细信息)