I have two tables Table_A and Table_B and i want to join those tables to optain Table_c as the result:
Table_A:
+-----------+-----------+---------+
| tableA_id | tableB_id | v_id |
+-----------+-----------+---------+
| 1 | 2 | 27 |
| 2 | 3 | 27 |
| 3 | 3 | 28 |
| 4 | 1 | 26 |
| 5 | 2 | 26 |
| 6 | 3 | 26 |
| 7 | 1 | 24 |
| 8 | 1 | 25 |
+-----------+-----------+---------+
Table_B:
+-----------+-----------+
| tableB_id | s_name |
+-----------+-----------+
| 1 | s1 |
| 2 | s2 |
| 3 | s3 |
+-----------+-----------+
Table_c:
+-----------+-----------+-----------++--------+
| tableB_id | s_name | tableA_id | v_id |
+-----------+-----------+-----------+---------+
| 1 | s1 | null | null |
| 2 | s2 | 1 | 27 |
| 3 | s3 | 2 | 27 |
+-----------+-----------+-----------+---------+
I tried different queries, but i couldn't reach the desired output.
This is MYSQL query: *Edit: reverse table order.
SELECT s.tableB_id, s.s_name, v.tableA_id, v.v_id
FROM Table_B as s
left OUTER JOIN Table_A as v
ON v.v_id=27
EDIT:
The result should be all Table_B data on left and assign to it table_A data if any or make it null. How can i make this?
Last Edit:
Here is a solution i came up with:
SELECT s.tableB_id , s.s_name, v.tableA_id, v.v_id
FROM Table_B s , Table_A v
WHERE v.v_id=27 AND v.tableB_id = s.tableB_id
UNION
SeLECT s.tableB_id , s.s_name, null as tableA_id, null as v_id
FROM Table_B s
WHERE s.tableB_id NOT IN (SELECT s.tableB_id
FROM Table_B s , Table_A v
WHERE v.v_id=27 AND v.tableB_id = s.tableB_id )
You could try:
SELECT tb.tableB_id, tb.s_name, ta.tableA_id, ta.v_id
FROM Table_B tb LEFT JOIN Table_A ta
ON tb.tableB_id = ta.tableB_id
To choose only one you could use:
SELECT tb.tableB_id, tb.s_name, ta.tableA_id, ta.v_id
FROM Table_B tb LEFT JOIN
(SELECT * FROM Table_A
WHERE v_id = 27) ta
ON tb.tableB_id = ta.tableB_id
SELECT distinct s.tableB_id, s.s_name, v.tableA_id, v.v_id
FROM Table_A as v
left OUTER JOIN Table_B as s
ON v.tableB_id =s.tableB_id and v.v_id = 27;
use this query hope fully you will get result
SELECT s.tableB_id, s.s_name, v.tableA_id, v.v_id
FROM Table_A as v
left OUTER JOIN Table_B as s ON s.tableB_id=v.tableB_id
WHERE v.v_id=27
Reverse the order, making it b LEFT JOIN a and add the condition for the common column (tableB_id):
SELECT s.tableB_id, s.s_name, v.tableA_id, v.v_id
FROM Table_B as s
LEFT OUTER JOIN Table_A as v
ON v.tableB_id = s.tableB_id
AND v.v_id=27 ;
Related
Blog table:
| bid | btitle |
| 29 | ...... |
| 38 | ...... |
likes table:
| lid | bid |
| 1 | 29 |
| 2 | 29 |
| 3 | 29 |
| 4 | 38 |
| 5 | 38 |
comment table
| commid | bid |
| 1 | 29 |
| 2 | 29 |
| 3 | 38 |
I had tried the following query but that will not work for me:
SELECT blog.bid,blog.btitle,COUNT(likes.lid) AS likecnt,COUNT(comment.comid) AS commentcnt FROM blog,likes,comment WHERE blog.bid=likes.bid AND blog.bid=comment.bid GROUP BY blog.bid
i want output like:
| bid | btitle | likecnt | commentcnt |
| 29 | ...... | 3 | 2 |
| 38 | ...... | 2 | 1 |
You can do left join with separate aggregation :
select b.bid, b.btitle,
coalesce(l.likecnt, 0) as likecnt,
coalesce(c.commentcnt, 0) as commentcnt
from blog b left join
(select l.bid, count(*) as likecnt
from likes l
group by l.bid
) l
on l.bid = b.bid left join
(select c.bid, count(*) as commentcnt
from comment c
group by c.bid
) c
on c.bid = l.bid;
If you want only matching bids the use INNER JOIN instead of LEFT JOIN & remove COALESCE().
Under many circumstances, correlated subqueries may be the fastest solution:
select b.bid, b.btitle,
(select count(*) from likes l where l.bid = b.bid) as num_likes,
(select count(*) from comment c where c.bid = b.bid) as num_comments
from blog b;
When is this a win performance wise. First, you want indexes on likes(bid) and comments(bid). With those indexes, it might be the fastest approach for your query.
It is particularly better if you have a where clause filtering the blogs in the outer query. It only has to do the counts for the blogs in the result set.
Use proper joins and count DISTINCT values because multiple joins increase the number of returned rows:
SELECT b.bid, b.btitle,
COUNT(DISTINCT l.lid) AS likecnt,
COUNT(DISTINCT c.comid) AS commentcnt
FROM blog b
LEFT JOIN likes l ON b.bid = l.bid
LEFT JOIN comment c ON b.bid = c.bid
GROUP BY b.bid, b.btitle
See the demo.
I use LEFT joins just in case there are no comments or likes for a post.
Results:
| bid | btitle | likecnt | commentcnt |
| --- | ------ | ------- | ---------- |
| 29 | ...... | 3 | 2 |
| 38 | ...... | 2 | 1 |
I have two tables
tbl1 and tbl2
tbl1 table contains 5 columns name id(pk), email , address ,pid(INDEX),status(ENUM Y,N)
tbl2 table contains 3 columns id(pk) ,pid(INDEX),domain
When i am running this query
SELECT *
FROM tbl1 as l
LEFT JOIN tbl2 as m on l.pid=m.pid
WHERE l.status='Y';
It is giving multiple records . Please note we are making join in pid both pid are not primary key. Please help to get only unique values from both table.
enter image description here
You seem to want to join on the basis of relative position in the tables.A way to do this is row_number simulation using variables.
drop table if exists t1,t2;
create table t1(id int, email varchar(5),address varchar(10),pid int,status varchar(1));
create table t2(id int, pid int, domain varchar(5));
insert into t1 values (1,'aa#aa', 'aaaaa',428,'Y'), (2,'bb#bb', 'bbbbb',428,'n'),(3,'cc#cc', 'ccccc',428,'Y') ;
insert into t2 values (1,428,'mmm'),(2,428,'zzz');
select t1.*,t2.*
from
(
select t1.*,
if(t1.pid <> #pid1, #bn1:=#bn1+1,#bn1:=#bn1) BlockNo1,
if(t1.id <> #id1, #rn1:=#rn1+1, #rn1:=1) rowno1,
#pid1:=t1.pid pid1,
#id1:=t1.id p1
from t1
cross join (select #bn1:=0,#rn1:=0, #pid1:=0 ,#id1:=0) r
where status = 'y'
order by t1.pid,t1.id
) t1
join
(
select t2.id t2id,t2.pid t2pid, t2.domain t2domain,
if(t2.pid <> #pid2, #bn2:=#bn2+1,#bn2:=#bn2) BlockNo2,
if(t2.id <> #id2, #rn2:=#rn2+1, #rn2:=1) rowno2,
#pid2:=t2.pid pid2,
#id2:=t2.id p2
from t2
cross join (select #bn2:=0,#rn2:=0, #pid2:=0 ,#id2:=0) r
order by t2.pid,t2.id
) t2 on (t1.blockno1 = t2.blockno2) and (t1.rowno1 = t2.rowno2)
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
| id | email | address | pid | status | BlockNo1 | rowno1 | pid1 | p1 | t2id | t2pid | t2domain | BlockNo2 | rowno2 | pid2 | p2 |
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
| 1 | aa#aa | aaaaa | 428 | Y | 1 | 1 | 428 | 1 | 1 | 428 | mmm | 1 | 1 | 428 | 1 |
| 3 | cc#cc | ccccc | 428 | Y | 1 | 2 | 428 | 3 | 2 | 428 | zzz | 1 | 2 | 428 | 2 |
+------+-------+---------+------+--------+----------+--------+------+------+------+-------+----------+----------+--------+------+------+
2 rows in set (0.04 sec)
I have three tables:
mysql> select * from a;
+----+---------+
| ID | Name |
+----+---------+
| 1 | John |
| 2 | Alice |
+----+---------+
mysql> select * from b;
+------+------------+----------+
| UID | date | received |
+------+------------+----------+
| 1 | 2017-10-02 | 5 |
| 1 | 2017-09-30 | 1 |
| 1 | 2017-09-29 | 4 |
+------+------------+----------+
mysql> select * from c;
+------+------------+------+
| UID | date | sent |
+------+------------+------+
| 1 | 2017-09-25 | 7 |
| 1 | 2017-09-30 | 2 |
| 1 | 2017-09-29 | 3 |
+------+------------+------+
If I try to calculate the total number of sent for John, it would be 12. And for received, it would be 10.
But if I try to join all three tables, the result is weird. Here is my query to join three tables:
mysql> select sum(sent), sum(received) from a
-> join c on c.UID = a.ID
-> join b on b.UID = a.ID
-> where a.ID = 1;
+-----------+---------------+
| sum(sent) | sum(received) |
+-----------+---------------+
| 36 | 30 |
+-----------+---------------+
But I need correct numbers (12 and 10, respectively). How can I have correct numbers?
You should join the aggregated result and not the raw tables
select a.uid, t1.received, t2.sent
from a
inner join (
select uid, sum(received) received
from b
group by uid
) t1 on t1.uid = a.id
inner join (
select uid, sum(sent) sent
from c
group by uid
) t2 on t2.uid = a.id
where a.id = 1
You could try below
select bx.id, recieved, sum(c.sent) sent from
(
SELECT a.id, sum(b.received) recieved
from a
INNER JOIN b
ON a.id=b.uid
group by a.id
) bx
INNER JOIN c
ON c.uid=bx.id
group by bx.id, bx.recieved;
>>>Demo<<<
This gets rid of the subquery, but introduces something else you might not want:
( SELECT uid, 'Received' AS direction, SUM(received) AS HowMany
WHERE uid = 1
GROUP BY uid )
UNION ALL
( SELECT uid, 'Sent' AS direction, SUM(sent) AS HowMany
WHERE uid = 1
GROUP BY uid )
So I've got 2 tables (simplified below)
members documents
------------ ------------------
id | name | registered id | member_id | type | expiry
---------------------- ------------------------------
1 | AAA | 1234567890 1 | 1 | 1 | 1234567890
2 | BBB | 1234567890 2 | 1 | 2 | 1234567891
3 | CCC | 1234567890 3 | 1 | 3 | 1234567892
4 | 2 | 1 | 1234567893
5 | 2 | 2 | 1234567894
6 | 2 | 3 | 1234567890
and I need to display these like this:
member id | name | doc 1 expiry | doc 2 expiry | doc 3 expiry
--------------------------------------------------------------
1 | AAA | 1234567890 | 1234567891 | 1234567892
2 | BBB | 1234567893 | 1234567894 | 1234567895
I've tried querying with multiple outer joins and aliases but it's just repeating the document expiry timestamps. This is what I have so far:
SELECT DISTINCT `members`.`id`, `members`.`name`, `a`.`expiry` AS `expiry1`, `b`.`expiry` AS `expiry2`, `c`.`expiry` AS `expiry3`
FROM `members`
LEFT OUTER JOIN `documents` a ON `a`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` b ON `b`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` c ON `c`.`member_id` = `members`.`id`
GROUP BY `members`.`id`
People need to be able to search through this, for example to list everyone whose document type 3 has expired.
Try
SELECT
a.id AS 'member id',
a.name
SUM(a.d1exp) AS 'doc 1 expiry',
SUM(a.d2exp) AS 'doc 2 expiry',
SUM(a.d3exp) AS 'doc 3 expiry'
FROM
(
SELECT
aa.id,
aa.name,
COALESCE(d1.expiry, 0) AS d1exp,
COALESCE(d2.expiry, 0) AS d2exp,
COALESCE(d3.expiry, 0) AS d3exp
FROM
members aa
LEFT JOIN
documents d1 ON aa.id = d1.member_id AND d1.type = 1
LEFT JOIN
documents d2 ON aa.id = d2.member_id AND d2.type = 2
LEFT JOIN
documents d3 ON aa.id = d3.member_id AND d3.type = 3
) a
GROUP BY
a.id,
a.name
This is assuming the values in the 'expiry' field are numerical.
mysql> select * from facts;
+----+---------+------------+---------+
| id | fact_id | fact_value | host_id |
+----+---------+------------+---------+
| 1 | 1 | rh5 | 1 |
| 2 | 1 | rh4 | 2 |
| 3 | 2 | virtual | 1 |
| 4 | 2 | virtual | 2 |
| 5 | 3 | rack 2 | 1 |
+----+---------+------------+---------+
mysql> select * from hosts;
+---------+-----------+
| host_id | host_name |
+---------+-----------+
| 1 | bellagio |
| 2 | mirage |
+---------+-----------+
The query I used does the following:
mysql> select host_name,fact_value from hosts as a left join facts as b on
> b.host_id=a.host_id and b.fact_id in (1,2,3);
+-----------+------------+
| host_name | fact_value |
+-----------+------------+
| bellagio | rh5 |
| bellagio | virtual |
| bellagio | rack 2 |
| mirage | rh4 |
| mirage | virtual |
+-----------+------------+
I want the results to print one row for each host, notice how it prints each fact_value on a separate row. The reason why i have the IN clause is that this table has over 40 possible columns for each host. I only want a handful (I select 3 in this example).
Here's what i'm looking for.
+-----------+--------+-----------+-----------+
| host_name | value1 | value 2 | value 3 |
+-----------+--------+-----------+-----------+
| bellagio | rh5 | virtual | rack 2 |
| mirage | rh4 | virtual | NULL |
+-----------+--------+-----------+-----------+
SELECT GROUP_CONCAT(fact_value)...
...
GROUP BY host_name
You could try creating a view on each of the value columns and then joining the columns.
create view [first_values] as
select fact_value, host_id
from facts where fact_id = 1;
create view [second_values] as
select fact_value, host_id
from facts where fact_id = 2;
create view [third_values] as
select fact_value, host_id
from facts where fact_id = 3;
now join the columns:
select h.host_name, f.fact_value as value1, s.fact_value as value2, t.fact_value as value3
from hosts as h
left join [first_values] as f on h.host_id = f.host_id
left join [second_values] as s on h.host_id = s.host_id
left join [third_values] as t on h.host_id = t.host_id;
This works ... granted some of the field names have changed since I last posted.
select distinct t0.host_id, t1.name, t2.value as os_type, t3.value as ip_addr, t4.value as rack, t5.value as host_owner, t6.value as host_memory,
t7.value as host_swap, t8.value as host_make, t9.value as host_model
FROM fact_values t0 left outer join hosts t1 on (t0.host_id=t1.id)
left outer join fact_values t2 on (t0.host_id=t2.host_id and t2.fact_name_id = 30)
left outer join fact_values t3 on (t0.host_id = t3.host_id and t3.fact_name_id = 13)
left outer join fact_values t4 on (t0.host_id = t4.host_id and t4.fact_name_id = 65)
left outer join fact_values t5 on (t0.host_id = t5.host_id and t5.fact_name_id = 81)
left outer join fact_values t6 on (t0.host_id = t6.host_id and t6.fact_name_id = 18)
left outer join fact_values t7 on (t0.host_id = t7.host_id and t7.fact_name_id = 51)
left outer join fact_values t8 on (t0.host_id = t8.host_id and t8.fact_name_id = 36)
left outer join fact_values t9 on (t0.host_id = t9.host_id and t9.fact_name_id = 47)
WHERE t1.name = '$hostname'
SELECT u.user_id,u2.acc_no AS pacc,u3.acc_no AS sacc
FROM table_name AS u
LEFT JOIN table_name AS u2 ON u2.user_id=u.user_id AND u2.acc_type='P' AND u2.lab_id = ? AND u2.category = 'SOMETHING'
LEFT JOIN table_name AS u3 ON u3.user_id=u.user_id AND u3.acc_type='S' AND u3.lab_id = ? AND u3.category = 'SOMETHING'
GROUP BY u.user_id
I have used the abouve query to get multiple rows to single row from the same table . Which is worked fine with me ..