SQL Query to join Two tables - mysql

I have two table as follows :-
table1 table2
date time amount date time amount
20120101 1000 101 20120104 1000 10
20120101 1100 100 20120104 1100 11
20120104 1000 101 20120105 1000 11
20120104 1100 105 20120105 1100 8
I want to join these two tables to get the output as follows :
date time table1-amt table2-amt
20120101 1000 101 NULL
20120101 1100 100 NULL
20120104 1000 101 10
20120104 1100 105 11
20120105 1000 NULL 11
20120105 1100 NULL 8
What is the sql query to get this output? I am using mysql database.
I tried following query:
select table1.date,table1.time,table1.close , table2.close
from table1,
table2
where table1.date=table2.date
and table1.time=table2.time;
it gave me output as
date time amount amount
20120104 1000 101 10
20120104 1100 105 11
People are directing me towards left outer join , full outer join I tried following two queries which did nt solve my purpose .
select * from table1 left join table2 on table1.date=table2.date ;
select * from table1 left join table2 on table1.date=table2.date union select * from table1 right join table2 on table1.date=table2.date;

An approach that only involves reading from each of the tables once:
SELECT `date`, `time`, sum(`amt1`) as `table1-amt`, sum(`amt2`) as `table2-amt`
FROM
(SELECT `date`, `time`, amount as amt1, null as amt2
FROM Table1
UNION ALL
SELECT `date`, `time`, null as am1, amount as amt2
FROM Table2) v
GROUP BY `date`, `time`
(As opposed to the examples linked in Yordi's answer, which each read from each table twice.)

This is what you want
Full Outer Join in MySQL
Not going to just give the answer, you'll find i there and learn some.
EDIT : Oh well someone beat me to it, and just handed it to you ^^.

You need a FULL (outer) JOIN. One way to achieve it in MySQL:
SELECT t1.date, t1.time, t1.close AS table1_amt, t2.close AS table2_amt
FROM table1 AS t1
LEFT JOIN table2 AS t2
ON t1.date = t2.date
AND t1.time = t2.time
UNION ALL
SELECT t2.date, t2.time, t1.close, t2.close
FROM table1 AS t1
RIGHT JOIN table2 AS t2
ON t1.date = t2.date
AND t1.time = t2.time
WHERE t1.date IS NULL ;

Related

mysql LEFT JOIN followed by GROUP BY with BETWEEN Ranges

I am stumped with how I should proceed. Here is my current LEFT JOIN command which works just fine:
SELECT t1.avg_temperature as T_aver,
t2.new_confirmed as count
FROM 3_day_avg as t1
LEFT JOIN table2 as t2 on t1.date = t2.date
And this works great to make this table:
T_aver |count|
-----------------
-0.2 | 2 |
3 | 2 |
5 | 1 |
-2.3 | 4 |
22 | 0 |
But now I want to take it one step further and group by ranges of T_aver (bins like 0-5, 6-10, 11-15, etc) and SUM() the count column. For example, If I was to place the range on the LEFT JOIN table example above of -10 to 0, and 0 to 30, the final table would look like this:
Trange |count|
-----------------
-10 - 0 | 6 |
0 - 30 | 3 |
This above transformation is where I am stumped and I fear to make my life simpler I just need to create one big table instead...
Thanks in advance
You were very close! Just start with your existing query and then wrap it.
For your bins use another lookup table if you don't want to be bound to a fixed interval:
bins:
mintemp | maxtemp
-10 | 0
0 | 30
I will use num instead of count, as I never use reserved words as columns:
SELECT
CONCAT(mintemp, ' - ', maxtemp) AS Trange,
SUM(baseview.num) AS num
FROM bins
INNER JOIN (
SELECT
t1.avg_temperature as T_aver,
t2.new_confirmed as num
FROM 3_day_avg as t1
LEFT JOIN table2 as t2 on t1.date = t2.date
) AS baseview
ON baseview.T_aver>bins.mintemp AND baseview.T_aver<=bins.maxtemp
GROUP BY bins.mintemp;
SELECT ranges.caption Trange,
SUM(t2.new_confirmed) as `count`
FROM 3_day_avg as t1
LEFT JOIN table2 as t2 on t1.date = t2.date
JOIN ( SELECT -10 t_from, 0 t_to, '-10 - 0' caption
UNION ALL
SELECT 0, 30, '0 - 30' ) ranges ON t1.avg_temperature >= ranges.t_from
AND t1.avg_temperature < ranges.t_to
GROUP BY ranges.caption;
It is better to create static ranges table instead of dynamically generated. This allows to create and to store a lot of pre-defined sets of ranges.
You can group by a CASE expression which contains your bins:
SELECT
CASE
WHEN t1.avg_temperature >= -10 and t1.avg_temperature <= 0 THEN '-10 - 0'
WHEN t1.avg_temperature > 0 and t1.avg_temperature <=30 THEN '0 - 30'
END AS Trange,
SUM(t2.new_confirmed) AS count
FROM 3_day_avg AS t1 LEFT JOIN table2 AS t2
ON t1.date = t2.date
GROUP BY Trange
You may add more bins in the CASE expression, change the ranges and the inequality signs to suit your requirement.

Get distinct values in union all in hive

I have a table in hive that looks something like this
cust_id prod_id timestamp
1 11 2011-01-01 03:30:23
2 22 2011-01-01 03:34:53
1 22 2011-01-01 04:21:03
2 33 2011-01-01 04:44:09
3 33 2011-01-01 04:54:49
so on and so forth.
For each record I want to check that how many unique products has this customer bought within the last 24 hrs excluding the current transaction. So the output should look something like this -
1 0
2 0
1 1
2 1
3 0
My hive query looks something like this
select * from(
select t1.cust_id, count(distinct t1.prod_id) as freq from temp_table t1
left outer join temp_table t2 on (t1.cust_id=t2.cust_id)
where t1.timestamp>=t2.timestamp
and unix_timestamp(t1.timestamp)-unix_timestamp(t2.timestamp) < 24*60*60
group by t1.cust_id
union all
select t.cust_id, 0 as freq from temp_table t2
)unioned;
Just get all the rows for last 24 hours do a group by on custid and count(distinct productid) -1 as the output. Overall query would look something like this.
select cust_id, COUNT(distinct prod_id) - 1 from table_name where
unix_timestamp(t1.timestamp)-unix_timestamp(t2.timestamp) < 24*60*60
GROUP BY cust_id
*I am subtracting 1 here to exclude the latest transactionid of the user. (hope this is what you meant)
You can join to a derived table that contains the distinct # of products purchased in the past 24 hours for each customer/timestamp pair.
select t1.cust_id, t1.prod_id, t1.timestamp, t2.count_distinct_prod_id - 1
from mytable t1
join (
select t2.cust_id, t2.timestamp, count(distinct t3.prod_id) count_distinct_prod_id
from mytable t2
join mytable t3 on t3.cust_id = t2.cust_id
where unix_timestamp(t2.timestamp) - unix_timestamp(t3.timestamp) < 24*60*60
group by t2.cust_id, t2.timestamp
) t2 on t1.cust_id = t2.cust_id and t1.timestamp = t2.timestamp

Mysql using count in query

Say that I have two tables T and T1
T
id p o
1 47 1
2 48 2
3 49 25
T1
id p o
1 47 1
2 42 2
3 47 25
I am looking to insert rows from T1 into T if count(T1.p)>1
T
id p o
1 47 1
2 48 2
3 49 25
1 47 1
3 47 25
I tried the following query but it didn't work
insert into T(id , p,o)(SELECT T1.id , T1.p1,T1.l FROM T1
where SELECT count(*) FROM t1
GROUP BY t1.p
HAVING COUNT(*)>1)
For more details .
Any help will be appreciated .
To get those values into T you will have to find out who they are in T1 and JOIN them with T1 again, to get the right number of rows:
INSERT INTO T (id, p, o)
SELECT TT.*
FROM T1 TT
INNER JOIN (
SELECT id, p1, l
FROM T1
GROUP BY p1
HAVING COUNT(*) > 1
) a ON a.p1 = TT.p1;
sqlfiddle demo
How this works:
SELECT id, p1, l
FROM T1
GROUP BY p1
HAVING COUNT(*) > 1
Returns the p1 that appears more than once in the table. This returns p1 = 47. GROUP BY p1 HAVING COUNT(*) > 1 makes sure that for each p1, we only want the results that appear more than once.
Then, we do an inner JOIN with T1 again, to get all rows that have P1 = 47:
ID P1 L
1 47 1
3 47 25
Then you just INSERT this result in the destination table.
You have a couple of errors in your select.
This should get you going:
SELECT T1.id , T1.p1,T1.l
FROM t1
GROUP BY t1.p1
HAVING COUNT(*)>1
SQL Fiddle
EDIT: Updated the SQL Fiddle to include the insert.
insert into T SELECT T1.id , T1.p1,T1.l FROM T1
GROUP BY t1.p1
HAVING COUNT(t1.p1)>1
http://www.sqlfiddle.com/#!2/75c8e/1
Use dml on the left side
The below SQL should do what your looking for:
INSERT INTO T (id, p, o)
SELECT id, p1, l
FROM T1
WHERE p1 IN (
SELECT p1
FROM T1
GROUP BY p1
HAVING COUNT(*) > 1
);
SQL Fiddle - Final result

Counting results of join on duplicate field

I have a table1 containing duplicate column value
Table1
id code
1 201202 0000 1111
2 201202 0000 9999
3 201203 0000 9999
4 201203 0000 0999
5 201204 1000 1999
6 201204 2000 2999
7 201205 3000 3999
8 201205 4000 4999
9 201205 5000 5999
Table 2
id numbers
1 2012020010
2 2012024929
3 2012033838
4 2012052434
5 2012052229
6 2012052232
I want to count all the numbers in table2 that are substring of distinct code in table 1
i.e. result should be
code frequency
201202 2
201203 1
201205 3
I have been able to get all the numbers for every code but can't figure out how to count them
SELECT DISTINCT table1.code , table1.id, table2.number AS ph_npa, count( * )
FROM table1
INNER JOIN table2 ON substr( table2.number, 1, 6 ) = table1.code
GROUP BY table1.number
any help is appreciated.
SELECT t1.code, COUNT(*) AS frequency
FROM table_one AS t1
LEFT JOIN table_two AS t2
ON t2.numbers LIKE CONCAT(t1.code, '%')
GROUP BY t1.code
Either use LEFT JOIN or INNER JOIN depending on if you want rows with frequency = 0 or not. All I did was basicly to run a LIKE as join condition with the % wildcard.
Try out the following. It can have performance hits on large data sets, but will get you started. It is working with my test data.
SELECT SUBSTR(t2.numbers, 1,6) AS CODE, COUNT(*) AS frequency
FROM table_2 t2
WHERE SUBSTR(t2.numbers, 1,6) IN (SELECT t1.code FROM table_1 t1)
GROUP BY SUBSTR(t2.numbers, 1,6)
Let me know if its working!
I'm not really one for using the "inner join" syntax and prefer to just use the cleaner looking implicit join on the data.
select
count(*)
from
npanxxsmall n, phone_numbers p
where
substr(n.code, 1, 6) = substr(p.number, 1, 6);
Let me know if this works!
ok I got it working and query is super fast
SELECT
DISTINCT A.code as code,
B.Counts AS frequency
FROM table1 AS A
INNER JOIN (
SELECT substr( number, 1, 6 ) AS subnumber, count( 1 ) AS Counts
FROM table2
GROUP BY substr( number, 1, 6 )
)
AS B ON A.code = B.subnumber
i.e.
select the number and frequency of number from table 2
and then join with distinct code form table 1

select values missing from one table based upon values in another table

I am using mysql and have 2 tables
table1
id
324
325
328
350
420
650
850
950
table2
id mapping_id
324 1
325 2
328 3
350 4
420 5
650 1
850 2
I want to produce a list of all the DISTINCT field mapping_ids that are missing for the ids in table one. For example id 850 has a mapping_id of 2 so is missing 1,3,4,5 and id 950 is not even in table 2 and so is missing 1,2,3,4,5. This should give me a distinct list of 1,2,3,4,5.
I have tried various LEFT JOIN queries but cannot get the results I need. Thanks in advance.
You could build a matrix of id - mapping combinations using a cross join. A not in subquery can determine which parts of the matrix are empty:
select *
from table1 t1
cross join
(
select distinct mapping_id
from table2
) mappings
where not exists
(
select *
from table2 t2
where t2.id = t1.id
and t2.mapping_id = mappings.mapping_id
)
select t1.id, t2.mapping_id
from table1 t1, table2 t2
MINUS
select t2.id, t2.mapping_id
from table1 t1
inner join table2 t2 on t1.id = t2.id