How can disjoint columns be selected in a single query? - mysql

I have 4 tables each with different columns but they all have one column in common. This is an integer identifier column. So I will have some integer x, and I want all the rows from all 4 tables that have this one id column equal to x.
I've tried something similar to:
SELECT table1.col1, table2.col2 FROM table1 LEFT JOIN table2 ON table1.id=x OR coastlinessports.id=x
And I get back rows which have both the columns from both tables in the same row.
So one result block would have:
table1.col1, table2.col2
But I really want:
table1.col1
tale2.col2
Is there a way I can do this without doing 4 select queries in a row?

If you want sequential rows from different tables, and for each table to return a different number of rows, then you can use UNION. However, UNION requires each SELECT to return the same number of columns, so you will need to fill in the missing columns with a value (or NULL), like this:
DROP TABLE IF EXISTS `table1`;
DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table1` (
`id` int(11) NOT NULL auto_increment,
`col1` VARCHAR(255),
`col2` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `table2` (
`id` int(11) NOT NULL auto_increment,
`col1` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO `table1` VALUES
(1, '1,1', '1,2'),
(2, '2,1', '2,2');
INSERT INTO `table2` VALUES
(1, '1,1'),
(2, '2,1');
SELECT `id`, `col1`, `col2` FROM `table1` WHERE `id` = 1
UNION
SELECT `id`, `col1`, NULL AS `col2` FROM `table2` WHERE `id` = 1;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1,1 | 1,2 |
| 1 | 1,1 | NULL |
+----+------+------+
If you want to further process the UNION result set, you can wrap it in another SELECT, like this:
SELECT `col1`, `col2` FROM (
SELECT `id`, `col1`, `col2` FROM `table1` WHERE `id` = 1
UNION
SELECT `id`, `col1`, NULL AS `col2` FROM `table2` WHERE `id` = 1
) AS `t1`
ORDER BY col2;
+------+------+
| col1 | col2 |
+------+------+
| 1,1 | NULL |
| 1,1 | 1,2 |
+------+------+
Is that what you are after?

This probably won't answer your question, but there's something weird about the JOIN.
Usually the "ON" condition refers to both tables being joined, similar to this:
... FROM table1 LEFT JOIN table2 ON table1.id = table2.id ...
I guess there can be cases where you wouldn't do that, but I can't think of any.

You should check out this post. It seems like what you are asking for:
http://ask.sqlteam.com/questions/870/pivoting-multiple-rows-into-one-row-with-multiple-columns

If the table is called the same you can use USING
And for the part of the given value, use WHERE
select * from table1 join table2 using(commonColumn) join table3 using(commonColumn) join table4 using(commonColumn) where commonColumn="desiredValue"
Update: on a second read of your question
You want this?
All rows of table1 where commonColumn="desiredValue"
Followed by
All rows of table2 where commonColumn="desiredValue"
Followed by
All rows of table3 where commonColumn="desiredValue"
Followed by
All rows of table4 where commonColumn="desiredValue"
If that's so, you need to use a UNION (and you have to make 4 selects)
IF the number of columns differs, you need to fill the gaps whit aliases
SELECT col1, col2, col3, col4 from table1 where commonColumn="desiredValue"
UNION
SELECT col1, col2, 0 as col3, 0 as col4 from table2 where commonColumn="desiredValue"
...

Related

How to delete rows from table1 that are present in table2 (MySQL)?

Consider MySQL tables: table1, table2
table1:
+------+------+
| col1 | col2 |
+------+------+
| 1 | a |
| 2 | b |
| 3 | c |
+------+------+
table2:
+------+------+
| col1 | col2 |
+------+------+
| 1 | a |
| 2 | b |
+------+------+
What is the most efficient way to delete the rows in table1 based on the rows in table2 such that the desired output looks like this:
+------+------+
| col1 | col2 |
+------+------+
| 3 | c |
+------+------+
Please note that this is a minimalist example of a problem I am having with two very large tables:
Here is code to create table1 and table2:
DROP TABLE IF EXISTS table1;
CREATE TABLE table1 (
col1 BIGINT,
col2 TEXT
);
INSERT INTO table1 VALUES (1, 'a');
INSERT INTO table1 VALUES (2, 'b');
INSERT INTO table1 VALUES (3, 'c');
DROP TABLE IF EXISTS table2;
CREATE TABLE table2 (
col1 BIGINT,
col2 TEXT
);
INSERT INTO table2 VALUES (1, 'a');
INSERT INTO table2 VALUES (2, 'b');
MySQL = 5.7.12
Question:
From reading this site and others I notice that there are several ways to do this operation in MySQL. I am wondering which is the fastest way for large tables (30M+ rows)? Here are some ways I have discovered:
1. method using DELETE
DELETE t1
FROM table1 t1
INNER JOIN table2 t2
ON t1.col1=t2.col1;
2. method using DELETE FROM
DELETE FROM t1
USING table1 t1
INNER JOIN table2 t2
ON ( t1.col1 = t2.col1 );
3. method using DELETE FROM
DELETE FROM table1 WHERE col1 in (SELECT col1 FROM table2);
Is there a faster way to do this that I have not listed here?
I will suggest another method it is not as practical as the mentioned method , but maybe it will be much faster for larger tables.
It is mentioned on [MySQL documentation] (https://dev.mysql.com/doc/refman/8.0/en/delete.html)
InnoDB Tables
If you are deleting many rows from a large table, you may exceed the lock table size for an InnoDB table. To avoid this problem, or
simply to minimize the time that the table remains locked, the
following strategy (which does not use DELETE at all) might be
helpful:
Select the rows not to be deleted into an empty table that has the same structure as the original table:
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
Use RENAME TABLE to atomically move the original table out of the way and rename the copy to the original name:
RENAME TABLE t TO t_old, t_copy TO t;
Drop the original table:
DROP TABLE t_old;
--Follow below steps:
--Rename the table:
RENAME TABLE table1 TO table1_old;
--Create new table with primary key and all necessary indexes:
CREATE TABLE table1 LIKE table1_old;
USE THIS FOR MyISAM TABLES:
SET UNIQUE_CHECKS=0;
LOCK TABLES table1_old WRITE, table2 WRITE;
ALTER TABLE table1 DISABLE KEYS;
INSERT INTO table1 (select * from table1_old t1 where col1 not in (select col1 from table2 ));
ALTER TABLE table1 ENABLE KEYS;
SET UNIQUE_CHECKS=1;
UNLOCK TABLES;
-- USE THIS FOR InnoDB TABLES:
SET AUTOCOMMIT = 0;
SET UNIQUE_CHECKS=0;
SET FOREIGN_KEY_CHECKS=0;
LOCK TABLES table1_old WRITE, table2 WRITE;
INSERT INTO table1 (select * from table1_old t1 where col1 not in (select col1 from table2 ));
SET FOREIGN_KEY_CHECKS=1;
SET UNIQUE_CHECKS=1;
COMMIT; SET AUTOCOMMIT = 1;
UNLOCK TABLES;
CREATE TABLE t_new LIKE t
INSERT INTO t_new
SELECT *
FROM t
LEFT JOIN exclude ON ...
WHERE exclude.id IS NULL;
RENAME TABLE t TO t_old,
t_new TO t;
DROP TABLE t_old;
DELETE (and UPDATE) choke on handling a huge number of rows; SELECT does not.
A possible optimization on this would be to drop all indexes except the PRIMARY KEY and re-add them after finishing.
(FOREIGN KEYs can be a big nuisance; do you have any?)

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

combine 3 or more tables, deliberately without a joining condition

How do i join 3 or more tables in mysql as follows?
there is a column for each column of each table (except ID)
ID field values all go into the same ID field in the new table
an additional column is added called table the values of which is the source Table name
an autoincremented newID field is added
only one table contributes to each row, unrelated fields have null values
total number of rows is equal to the sum records from all tables
example with just two tables :
TableA: TableB
ID | fieldA ID | fieldB
----------------- -----------------
1 | valueA1 1 | valueB1
2 | valueA2 2 | valueB2
ResultTable:
newID | ID | table | fieldA | fieldB
---------------------------------------------
1 | 1 | TableA | valueA1 |
2 | 2 | TableA | valueA2 |
3 | 1 | TableB | | valueB1
4 | 2 | TableB | | valueB2
I know this probably sounds a bit weird!. I am going to try and use this to batch insert nodes for records from various tables into neojs graph database with this batch-insert script. which could be hilarious considering I hardly know what I am doing in either database ;-) .
Try this one,
SELECT #rownum := #rownum + 1 AS NewID,
a.*
FROM
(
SELECT ID, fieldA, '' AS fieldB
FROM tableA
UNION ALL
SELECT ID, '' AS fieldA, fieldB
FROM tableB
) a, (SELECT #rownum:=0) r
SQLFiddle Demo
Create New Table
here's the proposed schema
CREATE TABLE Newtable
(
NewID INT AUTO_INCREMENT,
ID INT NOT NULL,
FieldA VARCHAR(30),
FieldB Varchar(30),
CONSTRAINT tb_pk PRIMARY KEY (NewID)
)
then Insert your values,
here's the query using INSERT INTO...SELECT statement
INSERT INTO NewTable (ID, fieldA, fieldB)
SELECT ID, fieldA, NULL AS fieldB
FROM tableA
UNION ALL
SELECT ID, NULL AS fieldA, fieldB
FROM tableB
Create a table with auto increment newID
Add all the possible columns allowing nulls.
INSERT INTO it the values from TableA, then TableB with something like:
INSERT INTO table
(ID, `table`, fieldA)
SELECT ID, 'TableA', fieldA FROM TableA
INSERT INTO table
(ID, `table`, fieldB)
SELECT ID, 'TableB', fieldB FROM TableB
Use UNION to select all rows in one result set, INSERT INTO for inserting to new table.
Also you can get new ID using ROW_NUMBER() in sql server
SELECT ID, COL1, NULL, NULL FROM Table1
UNION
SELECT ID, NULL, COL2, NULL FROM Table2
UNION
SELECT ID, NULL, NULL, COL3 FROM Table3
Select above result to a temp table. Use row number to update new ID
SELECT ID, ... , ROW_NUMBER() OVER(ORDER BY ID) AS NewID FROM #TempTable

Create a new table from merging two tables with union

I have two tables with the same columns.
I can merge them with UNION
select * from table1
union
select * from table2;
How do I create a new table with the same contents and columns as that query?
You can use CREATE TABLE ... SELECT statement.
CREATE TABLE new_table
SELECT * FROM table1
UNION
SELECT * FROM table2;
create table new_table as
select col1, col2 from table1
union
select col1, col2 from table2
Make sure you select same set of columns from tables in union.
Or even you can explicitly define create table (we generally use in our project).
CREATE TABLE IF NOT EXISTS auditlog (
user_id varchar(30) NOT NULL default '',
user_ip varchar(255) NOT NULL default '',
........
........
KEY ie1 (user_id) )
union=(auditlog_2,auditlog_3,auditlog_4) engine=merge insert_method=last;

Alternative to Intersect in 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);