问题
Within my application, I have a set of filters that can be applied when listing resources, which builds up a query by adding WHERE clauses, etc. before executing the query. This is using SQL Server 2008.
I have two pertinent tables, one which contains some static data about the resource, and another which can contain arbitrary/optional fields pertaining to that resource.
First table is something like this (table names & fields changed):
CREATE TABLE Resources (
ResID varbinary(28),
... extra stuff omitted
type integer );
The second table just has name/value pairs and the corresponding resource ID
CREATE TABLE ResourceFields (
ResID varbinary(28) NOT NULL,
Name nvarchar(255) NOT NULL,
Value nvarchar(1024) NOT NULL);
So, for this example, there could be multiple rows in 'ResourceFields' with name = 'ContactName' for the same ResID.
What I want to do is get a count of the number of rows in the 'Resources' table that have more than one 'ContactName' listed in 'ResourceFields' with 'type' equal to some value.
I came up with this (don't laugh -- I know just enough SQL to cause problems)
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;
but instead of returning the count of the number of rows (43 in my test set) in 'Resources', I get all the COUNT(rf.Value) values returned (that is, 43 individual counts).
What am I doing wrong?
回答1:
Just use your original query as a derived table (put it in a subselect):
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
回答2:
I am not really familiar with SQL Server but try:
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;
回答3:
You need to pre-aggregate the count of the 'ContactName' attributes. This is perhaps most easily accomplished with a 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
Some other things to consider -
Possibly make name
in ResourceFields
actually be a foreign key to a different table (so changing all attributes to a different text name is trivial). This would also allow you to put information about the expected format of data in value
in the referenced table, hopefully limiting invalid data (using regex masks, etc.) - you have to be extremely careful with multi-domain tables like this (generally, they shouldn't be used, but there are probably some use-cases).
Also, are you really anticipating storing 28 bytes worth of different resources? This is a rather large number... (remember that an Int is usually 4 bytes, and stores about 4 billion different values).
回答4:
Hope this helps:
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
UPDATE: Grouping removed from the subquery, which added irrelevant rows to the count.
来源:https://stackoverflow.com/questions/7029747/sql-query-to-get-count-of-rows-with-more-than-one-row-in-another-table