Alternative to Intersect in MySQL - mysql

I need to implement the following query in 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='恐慌') )
I know that intersect is not in MySQL. So I need another way.
Please guide me.

Microsoft SQL Server's INTERSECT "returns any distinct values that are returned by both the query on the left and right sides of the INTERSECT operand" This is different from a standard INNER JOIN or WHERE EXISTS query.
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 |
+-------+
With this particular question, the id column is involved, so duplicate values will not be returned, but for the sake of completeness, here's a MySQL alternative using INNER JOIN and DISTINCT:
SELECT DISTINCT value FROM table_a
INNER JOIN table_b
USING (value);
+-------+
| value |
+-------+
| B |
+-------+
And another example using WHERE ... IN and DISTINCT:
SELECT DISTINCT value FROM table_a
WHERE (value) IN
(SELECT value FROM table_b);
+-------+
| value |
+-------+
| B |
+-------+

There is a more effective way of generating an intersect, by using UNION ALL and GROUP BY. Performances are twice better according to my tests on large datasets.
Example:
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;
It is more effective, because with the INNER JOIN solution, MySQL will look up for the results of the first query, then for each row, look up for the result in the second query. With the UNION ALL-GROUP BY solution, it will query results of the first query, results of the second query, then group the results all together at once.

Your query would always return an empty recordset since cut_name= '全プロセス' and cut_name='恐慌' will never evaluate to true.
In general, INTERSECT in MySQL should be emulated like this:
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))
)
If both your tables have columns marked as NOT NULL, you can omit the IS NULL parts and rewrite the query with a slightly more efficient IN:
SELECT *
FROM mytable m
WHERE (col1, col2, col3) IN
(
SELECT col1, col2, col3
FROM othertable o
)

I just checked it in MySQL 5.7 and am really surprised how no one offered a simple answer: NATURAL JOIN
When the tables or (select outcome) have IDENTICAL columns, you can use NATURAL JOIN as a way to find intersection:
For example:
table1:
id, name, jobid
'1', 'John', '1'
'2', 'Jack', '3'
'3', 'Adam', '2'
'4', 'Bill', '6'
table2:
id, name, jobid
'1', 'John', '1'
'2', 'Jack', '3'
'3', 'Adam', '2'
'4', 'Bill', '5'
'5', 'Max', '6'
And here is the query:
SELECT * FROM table1 NATURAL JOIN table2;
Query Result:
id, name, jobid
'1', 'John', '1'
'2', 'Jack', '3'
'3', 'Adam', '2'

For completeness here is another method for emulating INTERSECT. Note that the IN (SELECT ...) form suggested in other answers is generally more efficient.
Generally for a table called mytable with a primary key called 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")
(Note that if you use SELECT * with this query you will get twice as many columns as are defined in mytable, this is because INNER JOIN generates a Cartesian product)
The INNER JOIN here generates every permutation of row-pairs from your table. That means every combination of rows is generated, in every possible order. The WHERE clause then filters the a side of the pair, then the b side. The result is that only rows which satisfy both conditions are returned, just like intersection two queries would do.

Starting from MySQL 8.0.31 the INTERSECT is natively supported.
INTERSECT Clause:
SELECT ...
INTERSECT [ALL | DISTINCT] SELECT ...
[INTERSECT [ALL | DISTINCT] SELECT ...]
INTERSECT limits the result from multiple SELECT statements to those rows which are common to all.
Sample:
SELECT 1 AS col
INTERSECT
SELECT 1 AS col;
-- output
1

Break your problem in 2 statements: firstly, you want to select all if
(id=3 and cut_name= '全プロセス' and cut_name='恐慌')
is true . Secondly, you want to select all if
(id=3) and ( cut_name='全プロセス' or cut_name='恐慌')
is true. So, we will join both by OR because we want to select all if anyone of them is true.
select * from emovis_reporting
where (id=3 and cut_name= '全プロセス' and cut_name='恐慌') OR
( (id=3) and ( cut_name='全プロセス' or cut_name='恐慌') )

AFAIR, MySQL implements INTERSECT through INNER JOIN.

SELECT
campo1,
campo2,
campo3,
campo4
FROM tabela1
WHERE CONCAT(campo1,campo2,campo3,IF(campo4 IS NULL,'',campo4))
NOT IN
(SELECT CONCAT(campo1,campo2,campo3,IF(campo4 IS NULL,'',campo4))
FROM tabela2);

Related

MySQL Using ORDER BY On Grouped (GROUP BY) Results

I am clearly misundersatanding something here with MySQL's GROUP BY as it is changing the order of my results.
Using this example SQL data:
CREATE TABLE IF NOT EXISTS `example_table` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`GROUP_NAME` text NOT NULL,
`ORDER_COLUMN` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
INSERT INTO `example_table` (`ID`, `GROUP_NAME`, `ORDER_COLUMN`) VALUES
(NULL, '271007K240.003:10', 70),
(NULL, '271007K240.003:10', 90),
(NULL, '271007K240.003:10', 100),
(NULL, '271007K240.003:10', 50),
(NULL, '271007K240.003:10', 80),
(NULL, '271007K240.003:10', 60);
Now I've created this data as an example so there would be lots of different values in the GROUP_NAME column., but for clairty I've just included what demonstrates the issue.
Running this very simple query, returns the highest ORDER_COLUMN (ID: 3) at the top as expected:
SELECT
*
FROM
`example_table`
ORDER BY
ORDER_COLUMN
DESC
However I've actually wanting to group by the column I've named here GROUP_NAME, sowith this in mind I was anting to do asomething like so:
SELECT
*
FROM
`example_table`
GROUP BY
GROUP_NAME
ORDER BY
ORDER_COLUMN
DESC
Now doing this just simply returns the first row, and ignores the ORDER BY.
I then thought to achieve what I need, I would need to use a sub-query with the data pre-sorted and then the group by can just group the sub-queries data-set like so:
SELECT
*
FROM
(
SELECT
*
FROM
`example_table`
ORDER BY
ORDER_COLUMN
DESC
) AS TEMP_TABLE
GROUP BY GROUP_NAME
Unfortunately though, this still returns just the first row of the table. What am I doing wrong here?
With this query:
select group_name, max(order_column) order_column
from example_table
group by group_name
you can get the max value of order_column for each id.
Then join it to the table:
select t.*
from example_table t inner join (
select group_name, max(order_column) order_column
from example_table
group by group_name
) g on g.group_name = t.group_name and g.order_column = t.order_column
See the demo.
Results:
| ID | GROUP_NAME | ORDER_COLUMN |
| --- | ----------------- | ------------ |
| 3 | 271007K240.003:10 | 100 |
Not completely sure what you want to accomplish, but did you try:
ORDER BY
GROUP_NAME,
ORDER_COLUMN
If that doesn't do the trick, how about adding more data with different group names and an example of what you expect the output to look like

Count most frequent element in a column in MySQL

I have the following question.
I have to columns and I want for each unique entry the first column the most frequent element of the second column. An Example would be:
COL A COL B
1 a
2 c
2 c
1 a
1 b
2 d
The query should output:
Col A COL B
1 a
2 c
Given this sample data:
CREATE TABLE t
(`a` int, `b` varchar(1))
;
INSERT INTO t
(`a`, `b`)
VALUES
(1, 'a'),
(2, 'c'),
(2, 'c'),
(1, 'a'),
(1, 'b'),
(2, 'd')
;
you first have to get the count for each with a query like this:
SELECT
a, b,
COUNT(*) AS amount
FROM
t
GROUP BY
a, b
Then you can use this query as a subquery to get the rows where a certain column holds the maximum. There's a nice article about this in the manual: The Rows Holding the Group-wise Maximum of a Certain Column
Choosing for example the last method described in said article, your final query would be this:
SELECT sq1.a, sq1.b FROM
(
SELECT
a, b,
COUNT(*) AS amount
FROM
t
GROUP BY
a, b
) sq1
LEFT JOIN
(
SELECT
a, b,
COUNT(*) AS amount
FROM
t
GROUP BY
a, b
) sq2 ON sq1.a = sq2.a AND sq1.amount < sq2.amount
WHERE sq2.amount IS NULL;
With this result:
+------+------+
| a | b |
+------+------+
| 1 | a |
| 2 | c |
+------+------+
Using a subselect in the SELECT clause is a simple way to solve your problem:
SELECT ColA, (SELECT ColB
FROM yourtable i
WHERE i.ColA = o.ColA
GROUP BY ColB
ORDER BY COUNT(*) DESC
LIMIT 1) AS ColB
FROM yourtable o
GROUP BY ColA;
o is just an alias for the outer query, i for the inner query. They're needed for the WHERE clause to work.
The above query is a result of the following query to find the most common occurence of ColB with a given ColA:
SELECT ColB
FROM yourtable
WHERE ColA = 1 -- Replace 1; this is where the magic happens in the above query
GROUP BY ColB
ORDER BY COUNT(*) DESC
LIMIT 1
you have to create My Sql function for this let say you function name is getMaxOccr so it will look like
CREATE FUNCTION `getMaxOccr`(val INT)
RETURNS varchar(25) CHARSET latin1
BEGIN
DECLARE answer VARCHAR(25) DEFAULT '';
SELECT colb FROM `tablename`
WHERE cola = val
ORDER BY COUNT(colb)
DESC INTO answer;
RETURN answer;
END
Once this function is created than you simply have to call
SELECT cola,getMaxOccr(cola) from tablename GROUP BY cola
this will give you the list with what you are looking for hope this helps

Join many tables sql [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to create a view of my database. \in fact, my database contains around 20 tables and i want to join the tables based on the foreign keys but there are some duplicates columns. Is there an easy and fast way to do it ?
Here's something that might help. You'll have to list out the columns if you do not want the dupes. You can run
SQL Fiddle Example
select group_concat(concat(table_name,'.', column_name) separator ', ')
from information_schema.columns
where table_name in ('Students', 'ClassRoster');
This will list [table_name].[column_name] for all the columns in the tables you specify in one long string. You can then copy the result and paste it next to the SELECT in your query and remove all the dupe columns if you know them. This query will show columns where there is more than one and show the table as well.
select table_name, column_name
from INFORMATION_SCHEMA.COLUMNS
where column_name in (
select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS
group by COLUMN_NAME
having count(1) > 1)
order by column_name
It still is manual but will save you some time. With a little more effort you could tweak the queries to where the whole process is just one query and not manually remove anything.
Just determined which columns you need in your view and use AS to assign a specific name to all of them.
This is an example. Both table have col1 and col2 :
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE Table1
(`Id` int, `Col1` varchar(1), `Col2` varchar(1), `Id2` int)
;
INSERT INTO Table1
(`Id`, `Col1`, `Col2`, `Id2`)
VALUES
(1, 'A', 'B', 1),
(2, 'B', 'C', 2),
(3, 'D', 'E', 3)
;
CREATE TABLE Table2
(`Id` int, `Col1` varchar(1), `Col2` varchar(1))
;
INSERT INTO Table2
(`Id`, `Col1`, `Col2`)
VALUES
(1, 'A', 'B'),
(2, 'B', 'C'),
(3, 'D', 'E')
;
Query 1:
SELECT Table1.Id as ID,
Table1.Col1 as COL1,
Table1.Col2 as COL2,
Table2.Col1 as COL3,
Table2.Col2 as COL4
FROM Table1
INNER JOIN Table2 ON Table1.Id2 = Table2.Id
Results:
| ID | COL1 | COL2 | COL3 | COL4 |
|----|------|------|------|------|
| 1 | A | B | A | B |
| 2 | B | C | B | C |
| 3 | D | E | D | E |
You Should Use Alias in joining like this...
Select E.Name , U.Name,E.Age,U.Age
From
TblEmployee E
inner join
TblUser U on E.EmployeeId = U.EmployeeId
Note : The above Query is only a Example So that you can go ahead
Edit: you can also do your column name what you want like this
Select E.* , U.*, E.Age as Employee Age ,U.Age as UserAge
/* you can specify some column by E.Name and if you do not want then simplye do E.* by doing thing every column of your that table will be selected */
From TblEmployee E
inner join
TblUser U on E.EmployeeId = U.EmployeeId

Convert columns into rows with inner join in mysql

Please take a look at this fiddle.
I'm working on a search filter select box and I want to insert the field names of a table as rows.
Here's the table schemea:
CREATE TABLE general
(`ID` int, `letter` varchar(21), `double-letters` varchar(21))
;
INSERT INTO general
(`ID`,`letter`,`double-letters`)
VALUES
(1, 'A','BB'),
(2, 'A','CC'),
(3, 'C','BB'),
(4, 'D','DD'),
(5, 'D','EE'),
(6, 'F','TT'),
(7, 'G','UU'),
(8, 'G','ZZ'),
(9, 'I','UU')
;
CREATE TABLE options
(`ID` int, `options` varchar(15))
;
INSERT INTO options
(`ID`,`options`)
VALUES
(1, 'letter'),
(2, 'double-letters')
;
The ID field in options table acts as a foreign key, and I want to get an output like the following and insert into a new table:
id field value
1 1 A
2 1 C
3 1 D
4 1 F
5 1 G
6 1 I
7 2 BB
8 2 CC
9 2 DD
10 2 EE
11 2 TT
12 2 UU
13 2 ZZ
My failed attempt:
select DISTINCT(a.letter),'letter' AS field
from general a
INNER JOIN
options b ON b.options = field
union all
select DISTINCT(a.double-letters), 'double-letters' AS field
from general a
INNER JOIN
options b ON b.options = field
Pretty sure you want this:
select distinct a.letter, 'letter' AS field
from general a
cross JOIN options b
where b.options = 'letter'
union all
select distinct a.`double-letters`, 'double-letters' AS field
from general a
cross JOIN options b
where b.options = 'double-letters'
Fiddle: http://sqlfiddle.com/#!2/bbf0b/18/0
A couple to things to point out, you can't join on a column alias. Because that column you're aliasing is a literal that you're selecting you can specify that literal as criteria in the WHERE clause.
You're not really joining on anything between GENERAL and OPTIONS, so what you really want is a CROSS JOIN; the criteria that you're putting into the ON clause actually belongs in the WHERE clause.
I just made this query on Oracle.
It works and produces the output you described :
SELECT ID, CASE WHEN LENGTH(VALUE)=2THEN 2 ELSE 1 END AS FIELD, VALUE
FROM (
SELECT rownum AS ID, letter AS VALUE FROM (SELECT DISTINCT letter FROM general ORDER BY letter)
UNION
SELECT (SELECT COUNT(DISTINCT LETTER) FROM general) +rownum AS ID, double_letters AS VALUE
FROM (
SELECT DISTINCT double_letters FROM general ORDER BY double_letters)
)
It should also run on Mysql.
I did not used the options table. I do not understand his role. And for this example, and this type of output it seems unnecessary
Hope this could help you to.

SELECT WHERE IN - mySQL

let's say I have the following Table:
ID, Name
1, John
2, Jim
3, Steve
4, Tom
I run the following query
SELECT Id FROM Table WHERE NAME IN ('John', 'Jim', 'Bill');
I want to get something like:
ID
1
2
NULL or 0
Is it possible?
How about this?
SELECT Id FROM Table WHERE NAME IN ('John', 'Jim', 'Bill')
UNION
SELECT null;
Start by creating a subquery of names you're looking for, then left join the subquery to your table:
SELECT myTable.ID
FROM (
SELECT 'John' AS Name
UNION SELECT 'Jim'
UNION SELECT 'Bill'
) NameList
LEFT JOIN myTable ON NameList.Name = myTable.Name
This will return null for each name that isn't found. To return a zero instead, just start the query with SELECT COALESCE(myTable.ID, 0) instead of SELECT myTable.ID.
There's a SQL Fiddle here.
The question is a bit confusing. "IN" is a valid operator in SQL and it means a match with any of the values (see here ):
SELECT Id FROM Table WHERE NAME IN ('John', 'Jim', 'Bill');
Is the same as:
SELECT Id FROM Table WHERE NAME = 'John' OR NAME = 'Jim' OR NAME = 'Bill';
In your answer you seem to want the replies for each of the values, in order. This is accomplished by joining the results with UNION ALL (only UNION eliminates duplicates and can change the order):
SELECT max(Id) FROM Table WHERE NAME = 'John' UNION ALL
SELECT max(Id) FROM Table WHERE NAME = 'Jim' UNION ALL
SELECT max(Id) FROM Table WHERE NAME = 'Bill';
The above will return 1 Id (the max) if there are matches and NULL if there are none (e.g. for Bill). Note that in general you can have more than one row matching some of the names in your list, I used "max" to select one, you may be better of in keeping the loop on the values outside the query or in using the (ID, Name) table in a join with other tables in your database, instead of making the list of ID and then using it.