在我的应用程序中,我有一组可以在列出资源时应用的过滤器,这些过滤器在执行查询之前通过添加WHERE子句等来构建查询。这是使用SQL Server 2008。
我有两个相关的表,一个包含有关资源的静态数据,另一个包含与该资源相关的任意/可选字段。
第一个表是这样的(表名和字段已更改):
CREATE TABLE Resources (
ResID varbinary(28),
... extra stuff omitted
type integer );
第二个表只有名称/值对和相应的资源ID
CREATE TABLE ResourceFields (
ResID varbinary(28) NOT NULL,
Name nvarchar(255) NOT NULL,
Value nvarchar(1024) NOT NULL);
因此,对于此示例,“ResourceFields”中可能有多行,其中name ='ContactName'表示相同的ResID。
我想要做的是获取'Resources'表中有多个'ContactName'的行数,这些'ContactName'在'ResourceFields'中列出,'type'等于某个值。
我想出了这个(不要笑 - 我知道足够的SQL导致问题)
SELECT count(r.ResID)
FROM Resources as r
INNER JOIN ResourceFields AS rf
ON rf.ResID = r.ResID
AND rf.name = 'ContactName'
WHERE r.type = 1
GROUP BY rf.ResID
HAVING COUNT(rf.Value) > 1;
但是不是在'Resources'中返回行数(我的测试集中的43)的计数,而是返回所有返回的COUNT(rf.Value)值(即43个单独的计数)。
我做错了什么?
答案 0 :(得分:8)
只需将原始查询用作派生表(将其放在子选择中):
SELECT COUNT(*)
FROM (
SELECT count(*) AS C
FROM Resources as r
INNER JOIN ResourceFields AS rf
ON rf.ResID = r.ResID
AND rf.name = 'ContactName'
WHERE r.type = 1
GROUP BY rf.ResID
HAVING COUNT(rf.Value) > 1;
) s
答案 1 :(得分:1)
我对SQL Server并不熟悉,但请尝试:
SELECT count( r.ResID ) FROM Resources as r where 1 < (select count(rf.value) from ResourceFields AS rf where rf.ResID = r.ResID AND rf.name = 'ContactName') and r.type = 1;
答案 2 :(得分:1)
您需要预先聚合“ContactName”属性的计数。这可能是CTE最容易实现的:
WITH Multiple_Contacts (ResID) as (SELECT a.ResID
FROM Resources as a
JOIN ResourceFields as B
ON b.ResID = A.ResID
AND b.name = 'ContactName'
WHERE a.type = 1
GROUP BY a.ResID
HAVING COUNT(a.ResId) > 1)
SELECT COUNT(ResId)
FROM Multiple_Contacts
需要考虑的其他事项 -
可能使name
中的ResourceFields
实际上是另一个表的外键(因此将所有属性更改为不同的文本名称是微不足道的)。这也允许您在value
中将有关预期数据格式的信息放在引用的表中,希望限制无效数据(使用正则表达式掩码等) - 您必须非常小心多域表,如这(通常不应该使用它们,但可能有一些用例)
另外,您真的希望存储28个字节值不同的资源吗?这是一个相当大的数字......(请记住,Int通常是4个字节,并存储大约40亿个不同的值)。
答案 3 :(得分:0)
希望这会有所帮助:
SELECT COUNT(*)
FROM Resources as r
WHERE EXISTS (
SELECT 1
FROM ResourceFields rf
WHERE rf.ResId = r.ResId
AND rf.name = 'ContactName'
HAVING COUNT(*) > 1
)
AND r.type = 1
更新:从子查询中删除分组,子查询将不相关的行添加到计数中。