用于查找与一组属性匹配的行的TSQL查询

用于查找与一组属性匹配的行的TSQL查询,sql,sql-server,tsql,Sql,Sql Server,Tsql,我得到了以下简化模式: CREATE TABLE [file] ( id UNIQUEIDENTIFIER NOT NULL, uri NVARCHAR(MAX) NOT NULL, CONSTRAINT PK_file PRIMARY KEY (id ASC) ON [PRIMARY] ) CREATE TABLE [property] ( id UNIQUEIDENTIFIER NOT NULL, name NVARCHAR(MAX) N

我得到了以下简化模式:

CREATE TABLE [file]
( 
    id UNIQUEIDENTIFIER NOT NULL, 
    uri NVARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_file PRIMARY KEY (id ASC) ON [PRIMARY] 
)

CREATE TABLE [property]
( 
    id UNIQUEIDENTIFIER NOT NULL, 
    name NVARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_property PRIMARY KEY (id ASC) ON [PRIMARY] 
)

CREATE TABLE [metadata]
( 
    fileid UNIQUEIDENTIFIER NOT NULL,
    propertyid UNIQUEIDENTIFIER NOT NULL,
    value NVARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_metadata PRIMARY KEY (fileid, propertyid ASC) ON [PRIMARY] 
)
其中
[fileid]
FKs到
[file].[id]
[propertyid]
FKs到
[property].[id]
。假设
[properyid]
聚集的
[value]
非聚集的

我想选择与某一组元数据匹配的所有文件;例如,每个文件的属性值对为
size=1kb
extension='txt'

我提出的查询(例如指定了三个属性)是:

SELECT [uri] FROM [file] WHERE [id] IN (
    SELECT a.[fileid] FROM (
        SELECT COUNT(*) [count], [fileid] FROM [metadata]
        WHERE ([propertyid] = '597ddddf-afd2-414f-9774-36f067038064' AND 
                [value] = N'moo') OR
              ([propertyid] = 'd83d12de-e4bc-4d18-be12-743504df3318' AND 
                [value] = N'foo') OR
              ([propertyid] = 'c00c3966-5034-4818-8567-abd660f37f15' AND 
                [value] = N'boo')
        GROUP BY [fileid]
    ) a
    WHERE a.[count] = 3
)

我能做得更好吗?

我可能遗漏了一些东西,但是如果您希望所有3个条件都得到满足,为什么不每次都使用“和”,而不是计算属性集的数量呢?您将避免不必要的分组

我会写:

    SELECT [uri] FROM [file] 
    WHERE EXISTS ( SELECT [fileid] FROM [metadata]
           WHERE [propertyid] = '597ddddf-afd2-414f-9774-36f067038064'
             AND [value] = N'moo'
             AND [propertyid] = 'd83d12de-e4bc-4d18-be12-743504df3318' 
             AND [value] = N'foo'
             AND [propertyid] = 'c00c3966-5034-4818-8567-abd660f37f15'
             AND [value] = N'boo'
             AND [file].[id] = [metadata].[fileid])

也许是这样的

SELECT 
   [uri] 
FROM 
   [file] 
WHERE 
   EXISTS(
        SELECT 
           NULL
        FROM 
           [metadata]
        WHERE 
              ([propertyid] = '597ddddf-afd2-414f-9774-36f067038064' AND 
                [value] = N'moo') OR
              ([propertyid] = 'd83d12de-e4bc-4d18-be12-743504df3318' AND 
                [value] = N'foo') OR
              ([propertyid] = 'c00c3966-5034-4818-8567-abd660f37f15' AND 
                [value] = N'boo') AND 
              [File].[id] = [metadata].[fileid]
        GROUP BY 
           [fileid]
        HAVING 
           COUNT(*) = 3
       )

你使用什么版本的SQL Server?我想我们支持2003年的所有版本,包括express.afaik,2000年和2005年。我相信你是对的,所以我想我们需要支持的可能是2005+版本。哇!停止在继续这样的设计之前,您需要立即停止并返回阅读数据库性能和设计方面的知识。你创建了一些永远不会很好执行的东西(出于很多原因,比如使用nvarchar(max),不能为一个表和另一个表建立索引),并且总是很难查询。我进行
计数
,因为我需要在
元数据中正好存在三行
;每个键值对一个。内部查询返回与任何键值对匹配的所有行,外部查询则说“只给我所有条件都匹配的
fileid
s”。您的查询断言
元数据
中存在一行,其中
属性ID
同时具有三个不同的值,因此它始终不返回任何值。顺便说一句,三个属性-值对是任意的,可以是任意数字。这看起来可能可行,一般来说,我看到这种问题可以通过为您要查找的每个属性连接一次元数据表来解决。
;WITH propertylist AS (
  SELECT propertyid = '597ddddf-afd2-414f-9774-36f067038064', value = N'moo' UNION ALL
  SELECT propertyid = 'd83d12de-e4bc-4d18-be12-743504df3318', value = N'foo' UNION ALL
  SELECT propertyid = 'c00c3966-5034-4818-8567-abd660f37f15', value = N'boo'
)
SELECT uri
FROM file
WHERE id IN (
  SELECT m.fileid
  FROM metadata m
    INNER JOIN propertylist p ON m.propertyid = p.propertyid AND m.value = p.value
  GROUP BY m.fileid
  HAVING COUNT(*) = (SELECT COUNT(*) FROM propertylist)
)