我有一个设置表,用'category'构造确定不同的产品,'varname'是变量名,'info'是设置的值。
所以,例如,
select top 6 category, varname, info
from settings_table
where NODE_NAME='HTT-COMM-A'
and section='Module Settings'
and category in ('ProductA', 'ProductB')
order by varname
结果:
category varname info ProductB WEB_ACCESS_ALLOW NO ProductA WEB_ACCESS_ALLOW NO ProductB WEB_ACCESS_BLOCK YES ProductA WEB_ACCESS_BLOCK YES ProductB WEB_ACCOUNT_DETAIL NO ProductA WEB_ACCOUNT_DETAIL YES
当category ='ProductA'和'ProductB'时,我想生成一个简单的值之间的差异列表。我可以想办法用临时表或一些子选择(例如,这个痛苦的子句)来做到这一点:
select a.category, a.varname, a.info , b.category, b.info
from (select category, varname, info, description
from settings_table
where category = 'ProductA') as a,
(select category, varname,info, description
from settings_table
where category = 'ProductB') as b
where a.varname=b.varname and a.info != b.info
但是当b中的varname不在a中时,上述方法(至少)会失败。 (任何解决方案都应该解决这个问题,a和b之间的varnames的任何差异都应该表示出来。)
这不是一个难以解决的难题,但是我想知道是否有一种'正确的方法'可以优雅地完成这项工作,没有可怕的子选择或没有上述警告。
这与SQL无关,但这个特定的表位于MSSQL服务器中。
谢谢, RK
答案 0 :(得分:2)
您可以使用自联接来完成此任务:
select a.varname as varname,
a.info as 'ProductA_Setting',
b.info as 'ProductB_Setting'
from @t a
inner join @t b
on a.varname = b.varname
where a.category = 'ProductA'
and b.category = 'ProductB'
and a.info <> b.info
以下是我用来测试的脚本:
declare @t table (category varchar(32), varname varchar(32), info varchar(32))
insert into @t select 'ProductB', 'WEB_ACCESS_ALLOW', 'NO'
insert into @t select 'ProductA', 'WEB_ACCESS_ALLOW', 'NO'
insert into @t select 'ProductB', 'WEB_ACCESS_BLOCK', 'YES'
insert into @t select 'ProductA', 'WEB_ACCESS_BLOCK', 'YES'
insert into @t select 'ProductB', 'WEB_ACCOUNT_DETAIL', 'NO'
insert into @t select 'ProductA', 'WEB_ACCOUNT_DETAIL', 'YES'
select * from @t
select a.varname as varname,
a.info as 'ProductA_Setting',
b.info as 'ProductB_Setting'
from @t a
inner join @t b
on a.varname = b.varname
where a.category = 'ProductA'
and b.category = 'ProductB'
and a.info <> b.info
答案 1 :(得分:2)
如果您只关心varname和info值,可以执行以下操作:
Select varname, info
From @Data As T
Except (
Select varname, info
From @Data As T1
Where category = 'ProductA'
Intersect
Select varname, info
From @Data As T2
Where category = 'ProductB'
)
如果您想要源表中的其他列,那么您可以执行以下操作:
Select T.*
From settings_table As T
Left Join (
Select T1.varname, T1.info
From settings_table As T1
Where T1.category = 'ProductA'
And T1.NODE_NAME='HTT-COMM-A'
And T1.section='Module Settings'
Intersect
Select T2.varname, T2.info
From settings_table As T2
Where T1.category = 'ProductB'
And T1.NODE_NAME='HTT-COMM-A'
And T1.section='Module Settings'
) As Z
On Z.varname = T.varname
And Z.info = T.info
Where Z.varname Is Null
And T.NODE_NAME='HTT-COMM-A'
And T.section='Module Settings'
然而第三种方法是简单地使用EXISTS谓词:
Select T.*
From settings_table As T
Where T.NODE_NAME='HTT-COMM-A'
And T.section='Module Settings'
And Not Exists (
Select 1
From settings_table As T2
Where T2.category In('ProductA','ProductB')
And T2.varname = T.varname
And T2.info = T.info
Group By T2.varname, T2.info
Having Count(*) = 2
)
答案 2 :(得分:1)
我想要使用CTE和完整的外部联接,我想:
WITH SETTINGS (category, varname, info)
AS
(
SELECT category, varname, info
FROM settings_table
WHERE NODE_NAME = 'HTT-COMM-A'
AND [section] = 'Module Settings'
AND category IN ('ProductA', 'ProductB')
)
SELECT
COALESCE(A.varname, B.varname) AS varname,
A.info AS info_a,
B.info AS info_b
FROM
SETTINGS A
FULL OUTER JOIN SETTINGS B
ON A.category = 'ProductA'
AND B.category = 'ProductB'
AND A.varname = B.varname
WHERE
A.varname IS NULL
OR B.varname IS NULL
OR A.info!= B.info
ORDER BY
COALESCE(A.varname, B.varname)
答案 3 :(得分:0)
SELECT ... EXCEPT和SELECT ... INTERSECT在我的书中总是有资格作为优雅,但这并不一定使代码更整洁或更容易阅读,我想出的版本仍然包含子查询。
基于 Paul Kearney -pk 的临时表,我想出了:
DECLARE
@Category1 varchar(32)
,@Category2 varchar(32)
SET @Category1 = 'ProductA'
SET @Category2 = 'ProductB'
SELECT isnull(set1.varname, set2.varname) varname, set1.Category, set1.Info, set2.Category, set2.Info
from (-- Exists for "1" but not for "2"
select @Category1 Category, varname, info
from @t
where category = @Category1
except select @Category1, varname, info
from @t
where category = @Category2) set1
full outer join (-- Exists for "2" but not for "1"
select @Category2 Category, varname, info
from @t
where category = @Category2
except select @Category2, varname, info
from @t
where category = @Category1) set2
on set2.varname = set1.varname
完整的外部联接会捕获缺少的行,并且在“类别”和“信息”列中最终会出现一些NULL。
答案 4 :(得分:0)
您发现了实体 - 属性 - 值数据模型的众多问题之一。对于程序员来说,这个模型非常诱人......它以轻松和简单的承诺引诱你。 “看,我可以添加一个没有DDL的新设置!”哇,太酷了。但是该表中的记录没有做任何事情,您仍然在添加代码来查找该设置,然后使用该设置。有了这些工作,添加新专栏真的是一个巨大的痛苦吗?
设置表是你唯一能够为EAV辩解的东西,但为什么呢?
通过教你捕鱼来回答你的问题,而不是递给你一个Fil'a'o'fish ......
Google =&gt; SQL JOIN TYPES
全部阅读,但重点是外部和全部外部连接