web-dev-qa-db-ja.com

MySQLのIntersectの代替

MySQLに次のクエリを実装する必要があります。

(select * from emovis_reporting where (id=3 and cut_name= '全プロセス' and cut_name='恐慌') ) 
intersect
( select * from emovis_reporting where (id=3) and ( cut_name='全プロセス' or cut_name='恐慌') )

交差はMySQLにはないことを知っています。だから私は別の方法が必要です。案内してください。

60
Ankur Jariwala

Microsoft SQL Serverの INTERSECT "INTERSECTオペランドの左側と右側の両方のクエリによって返される個別の値を返します"これは、標準のINNER JOINまたはWHERE EXISTSクエリとは異なります。

SQL Server

CREATE TABLE table_a (
    id INT PRIMARY KEY,
    value VARCHAR(255)
);

CREATE TABLE table_b (
    id INT PRIMARY KEY,
    value VARCHAR(255)
);

INSERT INTO table_a VALUES (1, 'A'), (2, 'B'), (3, 'B');
INSERT INTO table_b VALUES (1, 'B');

SELECT value FROM table_a
INTERSECT
SELECT value FROM table_b

value
-----
B

(1 rows affected)

MySQL

CREATE TABLE `table_a` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `value` varchar(255),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `table_b` LIKE `table_a`;

INSERT INTO table_a VALUES (1, 'A'), (2, 'B'), (3, 'B');
INSERT INTO table_b VALUES (1, 'B');

SELECT value FROM table_a
INNER JOIN table_b
USING (value);

+-------+
| value |
+-------+
| B     |
| B     |
+-------+
2 rows in set (0.00 sec)

SELECT value FROM table_a
WHERE (value) IN
(SELECT value FROM table_b);

+-------+
| value |
+-------+
| B     |
| B     |
+-------+

この特定の質問では、id列が関係するため、重複する値は返されませんが、完全を期すために、INNER JOINおよびDISTINCTを使用するMySQLの代替案を示します。

SELECT DISTINCT value FROM table_a
INNER JOIN table_b
USING (value);

+-------+
| value |
+-------+
| B     |
+-------+

WHERE ... INDISTINCTを使用した別の例:

SELECT DISTINCT value FROM table_a
WHERE (value) IN
(SELECT value FROM table_b);

+-------+
| value |
+-------+
| B     |
+-------+
55
Mike

UNION ALLおよびGROUP BYを使用して、交差を生成するより効果的な方法があります。大規模なデータセットでのテストによると、パフォーマンスは2倍向上しています。

例:

SELECT t1.value from (
  (SELECT DISTINCT value FROM table_a)
  UNION ALL 
  (SELECT DISTINCT value FROM table_b)
) AS t1 GROUP BY value HAVING count(*) >= 2;

INNER JOINソリューションでは、MySQLは最初のクエリの結果を検索し、次に各行で2番目のクエリの結果を検索するため、より効果的です。 UNION ALL-GROUP BYソリューションでは、最初のクエリの結果、2番目のクエリの結果をクエリし、結果を一度にグループ化します。

37
FBB

cut_name= '全プロセス' and cut_name='恐慌'trueに評価されないため、クエリは常に空のレコードセットを返します。

一般的に、INTERSECTMySQLは次のようにエミュレートする必要があります。

SELECT  *
FROM    mytable m
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    othertable o
        WHERE   (o.col1 = m.col1 OR (m.col1 IS NULL AND o.col1 IS NULL))
                AND (o.col2 = m.col2 OR (m.col2 IS NULL AND o.col2 IS NULL))
                AND (o.col3 = m.col3 OR (m.col3 IS NULL AND o.col3 IS NULL))
        )

両方のテーブルにNOT NULLとしてマークされた列がある場合、IS NULL部分を省略して、わずかに効率的なINでクエリを書き換えることができます。

SELECT  *
FROM    mytable m
WHERE   (col1, col2, col3) IN
        (
        SELECT  col1, col2, col3
        FROM    othertable o
        )
15
Quassnoi

私はMySQL 5.7でそれをチェックしましたが、誰も簡単な答えを提供していないことに本当に驚いています:NATURAL JOIN

テーブルまたは(選択結果)にIDENTICAL列がある場合、交差を見つける方法としてNATURAL JOINを使用できます。

enter image description here

例えば:

table1

id、名前、jobid

「1」、「ジョン」、「1」

「2」、「ジャック」、「3」

「3」、「アダム」、「2」

「4」、「請求書」、「6」

table2

id、名前、jobid

「1」、「ジョン」、「1」

「2」、「ジャック」、「3」

「3」、「アダム」、「2」

「4」、「請求書」、「5」

「5」、「最大」、「6」

そして、ここにクエリがあります:

SELECT * FROM table1 NATURAL JOIN table2;

クエリ結果:id、name、jobid

「1」、「ジョン」、「1」

「2」、「ジャック」、「3」

「3」、「アダム」、「2」

4
Payam

完全を期すために、INTERSECTをエミュレートする別の方法を紹介します。他の回答で提案されているIN (SELECT ...)形式の方が一般に効率的であることに注意してください。

一般に、mytableと呼ばれる主キーを持つidと呼ばれるテーブルの場合:

SELECT id
FROM mytable AS a
INNER JOIN mytable AS b ON a.id = b.id
WHERE
(a.col1 = "someval")
AND
(b.col1 = "someotherval")

(このクエリでSELECT *を使用すると、mytableで定義されている列の2倍の列を取得することに注意してください。これは、INNER JOINデカルト積 を生成するためです=)

ここのINNER JOINは、テーブルからすべての 順列 の行ペアを生成します。つまり、可能なすべての順序で、行のすべての組み合わせが生成されます。 WHERE句は、ペアのa側、次にb側をフィルターします。その結果、2つのクエリが交差するように、両方の条件を満たす行のみが返されます。

1
RobM

問題を2つのステートメントに分割します。まず、次の場合にすべてを選択します。

(id=3 and cut_name= '全プロセス' and cut_name='恐慌')

本当です。第二に、あなたはすべてを選択したい場合

(id=3) and ( cut_name='全プロセス' or cut_name='恐慌')

本当です。したがって、ORで両方を結合します。なぜなら、それらのいずれかが真である場合、すべてを選択するためです。

select * from emovis_reporting
    where (id=3 and cut_name= '全プロセス' and cut_name='恐慌') OR
        ( (id=3) and ( cut_name='全プロセス' or cut_name='恐慌') )
0
Nikhil Pareek