繁体   English   中英

选择所有行都匹配的ID

[英]Selecting id's where all rows match

我有两个表: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

因此,如果我使用以下标签查询:“ Firstname” =“ Chris”,“ Lastname” =“ Doe”,我希望结果为1。 如果我仅指定“ Firstname” =“ Chris”,则我希望同时使用1和2作为结果。

非常感谢您的帮助!


编辑:

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

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

使用count(*),我可以轻松找出所有输入键/值对是否匹配。 在性能方面如何运行?

好吧,您正在使用一个名为“键值”或“实体属性值”的数据库模型。

通常这不是最佳选择,您可以在以下问题中阅读更多有关此的内容:

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

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次键/值对的表联接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' 

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;

如果您事先知道所有可能的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' ...*/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM