SQLite 3 CROSS或INTERSECT复杂子查询

时间:2016-05-06 15:27:48

标签: sqlite

我有3张相关的表格。一个表有我正在寻找的行,另一个表有我需要搜索的数据,第三个表描述了我要查找的数据。我从以下查询中得到了不受欢迎的结果:

SELECT * FROM names WHERE namesKey IN ( SELECT namesKey FROM data WHERE 
    ( dataType IS 3 AND data IS 'COINCIDENCE' ) 
    AND ( dataType IS 2 AND data IS 'STATE' ) 
    AND ( dataType IS 1 AND data IS 'COUNTRY' ) );

我需要帮助根据过滤器表中的多行进行查询。我需要与第二个表中存在于多行上的键对应的行...我说的很糟糕......这是一个例子:

DROP TABLE IF EXISTS names ;
CREATE TABLE names (
    namesKey INTEGER PRIMARY KEY ASC,
    name TEXT NOT NULL
);
DROP TABLE IF EXISTS data ;
CREATE TABLE data (
    dataKey INTEGER PRIMARY KEY ASC,
    namesKey INTEGER NOT NULL,
    dataType INTEGER NOT NULL,
    data TEXT NOT NULL,
    FOREIGN KEY(namesKey) REFERENCES names(namesKey)
);
DROP TABLE IF EXISTS filter ;
CREATE TABLE filter (
    filterKey INTEGER PRIMARY KEY ASC,
    dataType INTEGER NOT NULL,
    data TEXT NOT NULL
);

INSERT INTO names( name ) VALUES ( 'name1' );
INSERT INTO names( name ) VALUES ( 'name2' );
INSERT INTO names( name ) VALUES ( 'name3' );
INSERT INTO names( name ) VALUES ( 'name4' );
INSERT INTO names( name ) VALUES ( 'name5' );
INSERT INTO names( name ) VALUES ( 'name6' );
INSERT INTO names( name ) VALUES ( 'name7' );
INSERT INTO names( name ) VALUES ( 'name8' );
INSERT INTO names( name ) VALUES ( 'name9' );

INSERT INTO data( namesKey, dataType, data ) VALUES ( 1, 1, 'COUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 1, 2, 'STATE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 1, 3, 'CITY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 2, 1, 'COUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 2, 2, 'STATE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 2, 3, 'OTHERCITY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 3, 1, 'COUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 3, 2, 'STATE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 3, 3, 'COINCIDENCE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 4, 1, 'COUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 4, 2, 'OTHERSTATE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 4, 3, 'COINCIDENCE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 5, 1, 'OTHERCOUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 5, 2, 'RANDOM' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 5, 3, 'COINCIDENCE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 6, 1, 'OTHERCOUNTRY' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 6, 2, 'OTHERSTATE' );
INSERT INTO data( namesKey, dataType, data ) VALUES ( 6, 3, 'COINCIDENCE' );

INSERT INTO filter( dataType, data ) VALUES ( 1, 'COUNTRY' );
INSERT INTO filter( dataType, data ) VALUES ( 2, 'STATE' );
INSERT INTO filter( dataType, data ) VALUES ( 3, 'COINCIDENCE' );

现在我需要的是能够相对可靠地运行3种不同类型的查询。

  1. 我需要搜索"无数据"并获得名称7,8和9

    • 这个很容易:

      SELECT * FROM names WHERE namesKey NOT IN ( SELECT namesKey FROM data ) ;
      
  2. 我需要根据数据表中的单一类型数据进行搜索

    • 同样简单,期望的结果3,4,5和6

      SELECT * FROM names WHERE 
          namesKey IN ( SELECT namesKey FROM data WHERE 
              ( dataType IS 3 AND data IS 'COINCIDENCE' ) ) 
      ;
      
  3. 我需要根据过滤表中的多行进行搜索。这个我不知道怎么做......

    • 所需结果仅为名称3行
    • 我可以通过

      来完成
      SELECT * FROM names WHERE 
          namesKey IN ( SELECT namesKey FROM data WHERE 
              ( dataType IS 3 AND data IS 'COINCIDENCE' ) )
          AND 
          namesKey IN ( SELECT namesKey FROM data WHERE 
              ( dataType IS 2 AND data IS 'STATE' ) )
          AND 
          namesKey IN ( SELECT namesKey FROM data WHERE 
              ( dataType IS 1 AND data IS 'COUNTRY' ) )
      ;
      
    • 但这只是丑陋的首都UGH!
  4. 更糟糕的是,使用这种方法,dataType在理论上是任意大的,因此我可能最终会尝试将数十个甚至数百个子查询串起来...我甚至在尝试之前我只能编写我的字符串。把它放到SQL中。 所以我正在寻找更优雅的解决方案。有什么建议?

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您可以使用:

float:left;

SqlFiddleDemo

输出:

SELECT * 
FROM names 
WHERE namesKey IN (SELECT namesKey 
                   FROM data 
                   WHERE dataType IS 3 AND data IS 'COINCIDENCE'
                   INTERSECT
                   SELECT namesKey 
                   FROM data 
                   WHERE dataType IS 2 AND data IS 'STATE'
                   INTERSECT
                   SELECT namesKey
                   FROM data
                   WHERE dataType IS 1 AND data IS 'COUNTRY'
                  );

或使用聚合:

╔═══════════╦═══════╗
║ namesKey  ║ name  ║
╠═══════════╬═══════╣
║        3  ║ name3 ║
╚═══════════╩═══════╝

SqlFiddleDemo2

答案 1 :(得分:1)

您可以直接将过滤器表与实际表连接以获取具有匹配项的行,然后仅检查所有三个搜索项匹配的那些名称键,即匹配行数与该数字相同的组所有搜索值:

SELECT namesKey
FROM data
JOIN filter USING (dataType, data)
GROUP BY namesKey
HAVING COUNT(*) = (SELECT COUNT(*) FROM filter);

然后像往常一样使用这些名称:

SELECT * 
FROM names 
WHERE namesKey IN (SELECT namesKey...);