选择所有行匹配的ID

时间:2016-02-19 13:33:19

标签: sql oracle

我有两个表:DOCUMENT和METADATA。 DOCUMENT存储ID和我们不感兴趣的一些信息,METADATA存储"标签"对于那些文件。标签由键和值组成。

因此,对于一个文档,DOCUMENT表中只有一个条目,但METADATA表中可能有很多条。

现在我需要的是传递一组键/值,并从METADATA表中仅检索与所有键/值匹配的文档。这意味着同时检查不同的行",好吧,我真的不知道该怎么做。

快速举例:

META_KEY | META_VALUE | META_DOCUMENT_ID
----------------------------------------
Firstname| Chris      | 1
Lastname | Doe        | 1
Firstname| Chris      | 2
Lastname | Moe        | 2

因此,如果我使用以下标签进行查询:"名字" ="克里斯","姓氏" =" Doe",我想要结果是1。如果我只指定"名字" ="克里斯"我想要1和2作为结果。

非常感谢您的帮助!

编辑:

如何计算必须匹配的标签数量? 像这样:

从元数据中选择meta_document_id,count(*),其中(meta_key ='名字'和meta_value ='克里斯')或(meta_key ='姓氏'和meta_value =' Doe')按meta_document_id分组

使用count(*),我可以很容易地找出所有输入键/值对是否匹配。如何运行性能?

3 个答案:

答案 0 :(得分:3)

嗯,您正在使用名为“key-value”或“Entity-attributte-value”的数据库模型。

这通常不是最佳选择,您可以在以下问题中详细了解:

对于这两种情况,您需要两个单独的查询:

SELECT distinct META_DOCUMENT_ID
FROM METADATA 
WHERE meta_key = 'Firstname' and meta_value = 'Chris'

SELECT distinct m1.META_DOCUMENT_ID
FROM METADATA m1
JOIN METADATA m2
ON m1.META_DOCUMENT_ID = m2.META_DOCUMENT_ID
WHERE m1.meta_key = 'Firstname' and m1.meta_value = 'Chris'
  AND m2.meta_key = 'Lastname' and m2.meta_value = 'Doe'

修改

  

我想我必须在表中加入N次键/值对吗?

这可以在没有连接的情况下完成,例如下面(假设每个id的meta_key值不超过1):

SELECT META_DOCUMENT_ID
FROM METADATA 
WHERE (meta_key, meta_value) IN
   ( ('Firstname' ,'Chris'), ('Lastname', 'Doe' ) )
GROUP BY META_DOCUMENT_ID
HAVING COUNT(*) = 2 /* 2 means that we are looking for 2 meta keys */
  

这将如何以性能方式运行?

苦头。请参阅上面关于此模型的链接的解释。

在许多情况下,此查询必须执行全表扫描(特别是当我们要查找的许多属性/键多于几个时),计算每个id的值,然后选择具有count = 2的这些id。

在规范化模型中,这是一个简单的查询,可以使用索引快速选择firstname ='Chris'的这几行

SELECT *
FROM table 
WHERE firstname = 'Chris' and lastname = 'Doe' 

答案 1 :(得分:2)

Oracle安装程序

CREATE TYPE KEY_VALUE_PAIR IS OBJECT (
  KEY   VARCHAR2(50),
  VALUE VARCHAR2(50)
);
/

CREATE TYPE KEY_VALUE_TABLE IS TABLE OF KEY_VALUE_PAIR;
/

CREATE TABLE meta_data ( meta_key, meta_value, meta_document_id ) AS
SELECT 'Firstname',   'Chris',    1 FROM DUAL UNION ALL
SELECT 'Lastname',    'Doe',      1 FROM DUAL UNION ALL
SELECT 'Phonenumber', '555-2368', 1 FROM DUAL UNION ALL
SELECT 'Firstname',   'Chris',    2 FROM DUAL UNION ALL
SELECT 'Lastname',    'Moe',      2 FROM DUAL UNION ALL
SELECT 'Phonenumber', '555-0001', 2 FROM DUAL;

<强>查询

SELECT meta_document_id
FROM   (
  SELECT meta_document_id,
         CAST(
           COLLECT(
             KEY_VALUE_PAIR( meta_key, meta_value )
           ) AS KEY_VALUE_TABLE
         ) AS key_values
  FROM   meta_data
  GROUP BY meta_document_id
)
WHERE  KEY_VALUE_TABLE(
         -- Your values here:
         KEY_VALUE_PAIR( 'Firstname', 'Chris' ),
         KEY_VALUE_PAIR( 'Lastname',  'Doe' )
       )
       SUBMULTISET OF key_values;

<强>输出

 META_DOCUMENT_ID
------------------
                1

更新 - 使用嵌套表格重新实现元数据表

Oracle安装程序

CREATE TYPE KEY_VALUE_PAIR IS OBJECT (
  META_KEY   VARCHAR2(50),
  META_VALUE VARCHAR2(50)
);
/

CREATE TYPE KEY_VALUE_TABLE IS TABLE OF KEY_VALUE_PAIR;
/

CREATE TABLE meta_data (
  meta_document_id INT,
  key_values       KEY_VALUE_TABLE
) NESTED TABLE key_values STORE AS meta_data_key_values;

CREATE UNIQUE INDEX META_DATA_KEY_VALUES_IDX ON META_DATA_KEY_VALUES (
  NESTED_TABLE_ID,
  META_KEY,
  META_VALUE
);
/

-- Insert everything in one go:
INSERT INTO META_DATA VALUES(
  1,
  KEY_VALUE_TABLE(
    KEY_VALUE_PAIR( 'Firstname',   'Chris' ),
    KEY_VALUE_PAIR( 'Lastname',    'Doe' ),
    KEY_VALUE_PAIR( 'Phonenumber', '555-2368' )
  )
);

-- Insert everything in bits:
INSERT INTO meta_data VALUE ( 2, KEY_VALUE_TABLE() );

INSERT INTO TABLE( SELECT key_values FROM meta_data WHERE meta_document_id = 2 )
  ( meta_key, meta_value ) VALUES( 'Firstname', 'Chris' );
INSERT INTO TABLE( SELECT key_values FROM meta_data WHERE meta_document_id = 2 )
  ( meta_key, meta_value ) VALUES( 'Lastname', 'Moe' );
INSERT INTO TABLE( SELECT key_values FROM meta_data WHERE meta_document_id = 2 )
  ( meta_key, meta_value ) VALUES( 'Phonenumber', '555-0001' );

--Select all the key-value pairs:
SELECT META_DOCUMENT_ID,
       META_KEY,
       META_VALUE
FROM   META_DATA md,
       TABLE( md.KEY_VALUES );

<强>查询

上述更改可让您简化查询:

SELECT META_DOCUMENT_ID
FROM   meta_data
WHERE  KEY_VALUE_TABLE(
         -- Your values here:
         KEY_VALUE_PAIR( 'Firstname', 'Chris' ),
         KEY_VALUE_PAIR( 'Lastname',  'Doe' )
       )
       SUBMULTISET OF key_values;

答案 2 :(得分:0)

如果您事先知道所有可能的TAGS,那么可能会有一些方法PIVOT

with METADATA (META_KEY, META_VALUE, META_DOCUMENT_ID) as
(
select 'Firstname', 'Chris',1 from dual union all
select 'Lastname', 'Doe',1 from dual union all
select 'Firstname', 'Chris',2 from dual union all
select 'Lastname', 'Moe',2 from dual
)
select *
from metadata
PIVOT  ( max (META_VALUE ) FOR (META_KEY) IN ('Firstname' AS Firstname, 'Lastname' AS Lastname))
where Firstname = 'Chris' /* and Lastname ='Doe' ...*/