#SQL - Compare different tables and create a new table - mysql

I have 4 tables with various columns where ID being the common value in all 4 tables. There is a column called EventDate in all 4 tables but with different values or NULL values for the same ID. The new table should have only ID and EventDate.
I would like to compare all the 4 tables based on the EventDate (ie) if two tables have the same date, it should insert the min date into the new table.

Use UNION ALL to combine all and take Minimum date for every ID
SELECT ID, MIN(EventDate) AS MIN_DTE INTO NEW_TABLE FROM (
SELECT ID, EventDate from TABLE1
UNION ALL
SELECT ID, EventDate from TABLE2
UNION ALL
SELECT ID, EventDate from TABLE3
UNION ALL
SELECT ID, EventDate from TABLE4
)A
GROUP BY ID

Related

SQL to get Union values if data exists in both the tables based on column

i have two tables (table1 and table2) with common column customer_id, with union and few filters i am getting all the values from table 1 and table2. I need only rows where both the tables have the data based on the common column customer_id. Below is the example.
The output that I need is as follows
Here's what I've tried:
SELECT customer_id,
age,
amount,
type
FROM table1
WHERE age > 5
UNION
SELECT customer_id,
age,
amount,
type
FROM table2
WHERE age > 5
Your query combines the rows of the two tables but doesn't match customers present in both. What you need to add is the condition on the "customer_id" being present in the corresponding other table:
SELECT *
FROM table1
WHERE age > 5 AND customer_id IN (SELECT customer_id FROM table2)
UNION
SELECT *
FROM table2
WHERE age > 5 AND customer_id IN (SELECT customer_id FROM table1)
You should choose between:
UNION, if you want to return unique rows between the two tables - makes an additional aggregation operation
UNION ALL, if you want to allow repeated rows between the two tables
If you don't have repeated identical rows in your tables, then you should go with the most efficient one, which is UNION ALL.

get count from multiple tables

I have 3 tables with a common 'type_id' column. its a foreign key from Table_type
Table_1 id,type_id,date...
Table_2 id,type_id,date...
Table_3 id,type_id,date...
Table_Type id, type_name, description
select type_id, count(*) from Table_1 GROUP BY type_id
gives the count from individual table.
i want to know how many times is a particular type used.
type_id, count(from 3 tables)
1 , 10
2 , 5
3 . , 3
Use union all and group by:
select type_id, count(*)
from ((select type_id from table_1) union all
(select type_id from table_2) union all
(select type_id from table_3)
) t
group by type_id
Get the counts from each table, combine those queries with UNION, and add up the counts.
SELECT type_id, SUM(count)
FROM (
SELECT type_id, COUNT(*) AS count
FROM table_1
UNION ALL
SELECT type_id, COUNT(*) AS count
FROM table_2
UNION ALL
SELECT type_id, COUNT(*) AS count
FROM table_3
) AS x
GROUP BY type_id
If there are indexes on the type_id column, this query should be able to take advantage of them. And the UNION processes smaller tables because it combines after the grouping.

SQL Find date range gaps in Table

Good day.
I seem to be struggling with what seems like a simple problem.
I have a table that has a value connected to a date (Monthly) for a finite number of ID's
ie. Table1
ID | Date ---| Value
01 | 2015-01 | val1
01 | 2015-02 | val2
02 | 2015-01 | val1
02 | 2015-03 | val2
So ID: 02 does not have a value for date 2015-02.
I would like to return all ID's and Dates that do not have a value.
Date range is: select distinct date from Table1
I can't seem to think outside the realms of selecting and joining on the same table.
I need to include the ID in my select to I can somehow select the ID and Date range that exists for that ID and compare to the entire date range, to get all the dates for each ID that isn't in the "entire" date range.
Please advise.
Thank you
Not very clear about your last two sentences. But you can play with the following query with different #max_days and #min_date:
-- DROP TABLE table1;
CREATE TABLE table1(ID int not null, `date` date not null, value varchar(64) not null);
INSERT table1(ID,`date`,value)
VALUES (1,'2015-01-01','v1'),(1,'2015-01-02','v2'),(2,'2015-01-01','v1'),(2,'2015-01-03','v2'),(4,'2015-01-01','v1'),(4,'2015-01-04','v2');
SELECT * FROM table1;
SET #day=0;
SET #max_days=5;
SET #min_date='2015-01-01';
SELECT i.ID,d.`date`
FROM (SELECT DISTINCT ID FROM table1) i
CROSS JOIN (
SELECT TIMESTAMPADD(DAY,#day,#min_date) AS `date`,#day:=#day+1 AS day_num
FROM table1 WHERE #day<#max_days) d
LEFT JOIN table1 t
ON t.ID=i.ID
AND t.`date`=d.`date`
WHERE t.`date` IS NULL
ORDER BY i.ID,d.`date`;
I now understand your requirement of dates being taken from the table; you want to find any gaps in the date ranges for each id.
This does what you need, but can probably be improved. Explanation below and you can view a working example.
DROP TABLE IF EXISTS Table1;
DROP TABLE IF EXISTS Year_Month_Calendar;
CREATE TABLE Table1 (
id INTEGER
,date CHAR(7)
,value CHAR(4)
);
INSERT INTO Table1
VALUES
(1,'2015-01','val1')
,(1,'2015-02','val2')
,(2,'2015-01','val1')
,(2,'2015-03','val1');
CREATE TABLE Year_Month_Calendar (
date CHAR(10)
);
INSERT INTO Year_Month_Calendar
VALUES
('2015-01')
,('2015-02')
,('2015-03');
SELECT ID_Year_Month.id, ID_Year_Month.date, Table1.id, Table1.date
FROM (
SELECT Distinct_ID.id, Year_Month_Calendar.date
FROM Year_Month_Calendar
CROSS JOIN
( SELECT DISTINCT id FROM Table1 ) AS Distinct_ID
WHERE Year_Month_Calendar.date >= (SELECT MIN(date) FROM Table1 WHERE id=Distinct_ID.ID)
AND Year_Month_Calendar.date <= (SELECT MAX(date) FROM Table1 WHERE id=Distinct_ID.ID)
) AS ID_Year_Month
LEFT JOIN Table1
ON ID_Year_Month.id = Table1.id AND ID_Year_Month.date = Table1.date
-- WHERE Table1.id IS NULL
ORDER BY ID_Year_Month.id, ID_Year_Month.date
Explanation
You need a calendar table which contains all dates (year/months) to cover the data you are querying.
CREATE TABLE Year_Month_Calendar (
date CHAR(10)
);
INSERT INTO Year_Month_Calendar
VALUES
('2015-01')
,('2015-02')
,('2015-03');
The inner select creates a table with all dates between the min and max date for each id.
SELECT Distinct_ID.id, Year_Month_Calendar.date
FROM Year_Month_Calendar
CROSS JOIN
( SELECT DISTINCT id FROM Table1 ) AS Distinct_ID
WHERE Year_Month_Calendar.date >= (SELECT MIN(date) FROM Table1 WHERE id=Distinct_ID.ID)
AND Year_Month_Calendar.date <= (SELECT MAX(date) FROM Table1 WHERE id=Distinct_ID.ID)
This is then LEFT JOINED to the original table to find the missing rows.
If you only want to return the missing row (my query displays the whole table to show how it works), add a WHERE clause to restrict the output to those rows where an id and date is not returned from Table1
Original answer before comments
You can do this without a tally table, since you say
Date range is: select distinct date from Table1
I've slightly changed the field names to avoid reserved words in SQL.
SELECT id_table.ID, date_table.`year_month`, table1.val
FROM (SELECT DISTINCT ID FROM table1) AS id_table
CROSS JOIN
(SELECT DISTINCT `year_month` FROM table1) AS date_table
LEFT JOIN table1
ON table1.ID=id_table.ID AND table1.`year_month` = date_table.`year_month`
ORDER BY id_table.ID
I've not filtered the results, in order to show how the query is working. To return the rows where only where a date is missing, add WHERE table1.year_month IS NULL to the outer query.
SQL Fiddle
You will need a tally table(s) or month/year tables. So you can then generate all of the potential combinations you want to test with. As far as exactly how to use it your example could use some expanding on such as last 12 months, last3 months, etc. but here is an example that might help you understand what you are looking for:
http://rextester.com/ZDQS5259
CREATE TABLE IF NOT EXISTS Tbl (
ID INTEGER
,Date VARCHAR(10)
,Value VARCHAR(10)
);
INSERT INTO Tbl VALUES
(1,'2015-01','val1')
,(1,'2015-02','val2')
,(2,'2015-01','val1')
,(2,'2015-03','val1');
SELECT yr.YearNumber, mn.MonthNumber, i.Id
FROM
(
SELECT 2016 as YearNumber
UNION SELECT 2015
) yr
CROSS JOIN (
SELECT 1 MonthNumber
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9
UNION SELECT 10
UNION SELECT 11
UNION SELECT 12
) mn
CROSS JOIN (
SELECT DISTINCT ID
FROM
Tbl
) i
LEFT JOIN Tbl t
ON yr.YearNumber = CAST(LEFT(t.Date,4) as UNSIGNED)
AND mn.MonthNumber = CAST(RIGHT(t.Date,2) AS UNSIGNED)
AND i.ID = t.ID
WHERE
t.ID IS NULL
The basic idea to determine what you don't know is to generate all possible combinations of something could be. E.g. Year X Month X DISTINCT Id and then join back to figure out what is missing.
Probably not the prettiest but this should work.
select distinct c.ID, c.Date, d.Value
from (select a.ID, b.Date
from (select distinct ID from Table1) as a, (select distinct Date from Table1) as b) as c
left outer join Table1 d on (c.ID = d.ID and c.Date = d.Date)
where d.Value is NULL

Insert into table with multiple rows in subquery

I want to have results in a table where the data comes from 3 different tables.
For that I have tried to execute this query:
INSERT INTO sometable (id,date)
VALUES
(
(SELECT id FROM table1
UNION
SELECT id FROM table2
UNION
SELECT id FROM table3)
,
(SELECT date FROM table1
UNION
SELECT date FROM table2
UNION
SELECT date FROM table3)
)
The result of this query is an error stating cannot insert multiple rows. Please help me to write this query correctly.
The INSERT ... SELECT syntax is different to the INSERT ... VALUES syntax. Also, you want to select both columns from each table at the same time:
INSERT INTO sometable (id, date)
SELECT id, date FROM table1 UNION
SELECT id, date FROM table2 UNION
SELECT id, date FROM table3

How to Select max Value from 2 tables in MySQL

I have 2 tables in MySQL DB.
Both the tables have a column as ID which is of type int(10) unsigned.
Table1 has no data and Table2 has the ID as 24.
I am using the below query to get the max ID
select max(ID) from
(
select IFNULL(max(ID),0) as ID from table1
UNION
select IFNULL(max(ID),0) as ID from table2
)temp;
I am expecting the value 24 but it gives 0.
Anything wrong in my query? Please help.
try this,
SELECT IFNULL(MAX(ID), 0) ID
FROM
(
SELECT ID FROM table1
UNION ALL
SELECT ID FROM table2
) a