How to join 5 tables MYSQL with specific condition - mysql

i have 5 tables below
tb_satker
kdsatker
1
2
3
tb_akun
akun | code
A | 1
B | 2
C | 3
tb_simponi
kdsatker | akun | jumlah
1 | A | 100
1 | B | 200
tb_span
kdsatker | akun | jumlah
1 | A | 1
1 | B | 2
1 | C | 3
tb_upt
kdsatker | akun | jumlah
1 | A | 10
1 | B | 20
1 | C | 30
What i need is output to something like this
kdsatker | akun | simponi | span | upt
1 | A | 100 | 1 | 10
1 | B | 200 | 2 | 20
1 | C | 0 | 3 | 30
2 | 0 | 0 | 0 | 0
3 | 0 | 0 | 0 | 0
I've try using sql fiddle but the result is not right (http://sqlfiddle.com/#!9/e83ce7/10)
SELECT tb_satker.kdsatker,tb_akun.akun,tb_simponi2.simponi,tb_span2.span,tb_upt2.upt
FROM tb_satker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_simponi.jumlah) as simponi FROM tb_simponi GROUP BY kdsatker,akun)
as tb_simponi2 ON tb_simponi2.kdsatker=tb_satker.kdsatker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_span.jumlah) as span FROM tb_span GROUP BY kdsatker,akun)
as tb_span2 ON tb_span2.kdsatker=tb_satker.kdsatker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_upt.jumlah) as upt FROM tb_upt GROUP BY kdsatker,akun)
as tb_upt2 ON tb_upt2.kdsatker=tb_satker.kdsatker
LEFT JOIN
tb_akun ON tb_akun.akun=tb_simponi2.akun AND
tb_akun.akun=tb_span2.akun AND
tb_akun.akun=tb_upt2.akun
GROUP BY tb_satker.kdsatker,tb_akun.akun
Can anybody help me with the right idea??
Many Thanks

Your inner queries are all based on a two-part group by two parts... kdsatker and akun.
Since it is possible for any of the tb_simponi, tb_span, tb_upt can have any combination,
I would pre-union all possible combinations of those FIRST. THEN, Join to the summary results.
and FINALLY get the akun and kdsatker components. Something like...
SELECT
tb_satker.kdsatker,
coalesce( tb_akun.akun, 0 ) akun,
coalesce( tb_simponi2.simponi, 0 ) simponi,
coalesce( tb_span2.span, 0 ) span,
coalesce( tb_upt2.upt, 0 ) upt
FROM
tb_satker
LEFT JOIN
( SELECT distinct kdsatker, akun FROM tb_simponi
UNION
SELECT kdsatker, akun FROM tb_span
UNION
SELECT kdsatker, akun FROM tb_upt
) AllKdAkun
on tb_satker.kdsatker = AllKdAkun.kdsatker
LEFT JOIN tb_akun
on AllKdAkun.akun = tb_akun.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_simponi.jumlah) as simponi
FROM tb_simponi
GROUP BY kdsatker, akun ) as tb_simponi2
ON AllKdAkun.kdsatker = tb_simponi2.kdsatker
AND AllKdAkun.Akun = tb_simponi2.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_span.jumlah) as span
FROM tb_span
GROUP BY kdsatker, akun ) as tb_span2
ON AllKdAkun.kdsatker = tb_span2.kdsatker
AND AllKdAkun.akun = tb_span2.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_upt.jumlah) as upt
FROM tb_upt
GROUP BY kdsatker, akun) as tb_upt2
ON AllKdAkun.kdsatker = tb_upt2.kdsatker
AND AllKdAkun.akun = tb_upt2.akun
No final group by at the outer level.
First level is your tb_satker. There may (or not) be a record in any of the subsidiary tables, so that is first.
Second level is a distinct list of every kdsatker, akun in ANY of the other 3 tables. So now you can LEFT JOIN kdsatker thus keeping every record including 1, 2, 3 even though 2 & 3 have no records.
From the second level, you can now left-join to the tb_akun table which in this case, only kdsatker is the only one with records for any given akun.
Finally joining the pre-union list of all combinations grouped by kdsatker, akun are able to be matched for their final summary into the final list.
Hope each step makes sense to what you appear to be trying for.

Related

MySQL Summing & Counting Child Values in Another Table

BOOKINGS TABLE
id | price | anotherVal
-----------------------------
1 | 10000 | *
2 | 20000 | *
3 | 1000 | *
4 | 8000 | *
BOOKING PAYMENTS TABLE
id | bookingId | amount | currencyId | mxnAmount
--------------------------------------------------
1 | 1 | 100.00 | 1 | 100.00
2 | 1 | 300.00 | 3 | 6400.00
3 | 2 | 500.21 | 1 | 500.21
4 | 4 | 123.95 | 6 |
4 | 4 | 800.00 | 1 | 800.00
I need to get all BOOKINGS_TABLE columns and then for each booking add up the mxnAmount column, but also the result should tell if all rows in BOOKING_PAYMENTS_TABLE had an mxnAmount so i can know if the mxnAmount is final or there's some rows left to be updated, i have a query that works for the first part:
SELECT b.*, SUM(p.mxnAmount) FROM bookings b LEFT JOIN bookingPayments p ON b.id = p.bookingId GROUP BY b.id
I figured i could make us of COUNT() to count all rows in BOOKING_PAYMENTS_TABLE but then how can i get the number for the rows that have an mxnAMOUNT?
SELECT b.*, SUM(p.mxnAmount), COUNT(p.id) FROM bookings b LEFT JOIN bookingPayments p ON b.id = p.bookingId GROUP BY b.id
I tried this:
SELECT b.*, SUM(p.mxnAmount), COUNT(p.id), COUNT(pp.id) FROM bookings b LEFT JOIN bookingPayments p ON b.id = p.bookingId LEFT JOIN bookingPayments pp ON b.id = pp.bookingId WHERE pp.mxnAmount IS NOT NULL GROUP BY b.id
But then the query returns only bookings that have all their payments rows with an mxnAmount, any leads?
I figured i could make us of COUNT() to count all rows in BOOKING_PAYMENTS_TABLE but then how can i get the number for the rows that have an mxnAMOUNT?
Just COUNT() that particular column: this gives you the number of non-null values in the column for each group:
SELECT b.*, SUM(p.mxnAmount), COUNT(p.id), COUNT(p.mxnAmount)
FROM bookings b
LEFT JOIN bookingPayments p ON b.id = p.bookingId
GROUP BY b.id
If you want to know if any mxmamount in the group is missing, you can do:
MAX(p.id IS NOT NULL AND p.mxnAmount IS NULL) has_missing_mxnAmount

SQL: Get an article for each category

There are two tables article and category.
nid | title | status
---+-------------+-------
1 | abc | 1
2 | ggg | 1
3 | kkk | 0
4 | rrr | 1
5 | fff | 1
6 | ggg | 1
Where status = 1 is published.
cid | nid
---+-------------
1 | 1
2 | 2
2 | 3
3 | 4
1 | 5
2 | 6
Now I want to get a one nid for each cid, no double occurrence of cid where status is 1.
You can use GROUP BY with JOIN, e.g.:
SELECT t2.cid, MAX(t2.nid)
FROM table2 t2 JOIN table1 t1 ON t2.nid = t1.nid and t1.status = 1
GROUP BY t2.cid;
First of all you must decide which nid to show for a cid in case of multiple matches. Let's say you want the maximum nid. Select from category and look up articles for their status. Then aggregate.
select cid, max(nid)
from category
where nid in (select nid from article where status = 1)
group by cid;
You can use aggregation:
select c.cid, max(c.nid)
from category c join
article a
on c.nid = a.nid
where a.status = 1
group by c.cid;
Try this one.
SELECT DISTINCT cid
FROM category AS a1
INNER JOIN article AS a2 ON a1.nid = a2.nid
WHERE a1.[STATUS] = 1

How to get count for each row mysql query?

I have Three tables
1)review_trans
2)user_comment_trans
3)helpful_review_trans
The table structure looks like this
review_trans
review_id(pk) | review_desc | user_id
--------------+----------------+-----------
1 | hello world | 1
2 | test2 | 1
3 | test3 | 2
user_comment_trans
comment_id | review_id | user_id
------------+--------------+------------
1 | 1 | 4
2 | 1 | 2
3 | 2 | 3
helpful_review_trans
helpful_review_id | review_id | user_id
------------------+------------+------------
1 | 1 | 4
2 | 1 | 2
3 | 2 | 3
I want count on each review for helpful votes and comments.
So output i want is like this
OUTPUT
review_id review_desc count(helpful_review_id) count(comment_id)
------------+------------------+----------------------------+--------------------
1 | hello world | 2 | 2
2 | test2 | 1 | 1
3 | test3 | |
Iam unable to get this record.I tried joining the tables but it only shows just one review_desc
Please advise and help.
Use left join with count(distinct)
select r.review_id,
r.review_desc,
count(distinct u.comment_id),
count(distinct h.helpful_review_id)
from review_trans r
left join user_comment_trans u on(r.review_id = u.review_id)
left join helpful_review_trans h on(r.review_id = h.review_id)
group by r.review_id
Demo
SELECT rt.review_id, rt.review_desc,
COUNT(DISTINCT hrt.helpful_review_id), COUNT(DISTINCT uct.comment_id)
FROM review_trans rt
LEFT JOIN helpful_review_trans hrt ON rt.review_id = hrt.review_id
LEFT JOIN user_comment_trans uct ON uct.review_id = rt.review_id
GROUP BY rt.review_id
SELECT rt.review_id, rt.review_desc, helpful_count, comment_count
FROM review_trans AS rt
LEFT JOIN (
SELECT review_id, COUNT(*) AS comment_count
FROM user_comment_trans
GROUP BY review_id) AS uct ON rt.review_id = uct.review_id
LEFT JOIN (
SELECT review_id, COUNT(*) AS helpful_count
FROM helpful_review_trans
GROUP BY review_id) AS hrt ON rt.review_id = hrt.review_id
You could do this:
SELECT
review_trans.review_id,
review_trans.review_desc,
(
SELECT
COUNT(*)
FROM
helpful_review_trans
WHERE
helpful_review_trans.review_id=review_trans.review_id
) AS helpful_review_id,
(
SELECT
COUNT(*)
FROM
user_comment_trans
WHERE
user_comment_trans.review_id=review_trans.review_id
) AS CountComment_id
FROM
review_trans

Query also returns column with value 0

I have two tables:
tb_question
**id_quest** | **desc_quest**
1 | How do you do...?
2 | How are you...?
tb_answer
**id_quest** | **date_answer**
1 | 2013/11/25
1 | 2013/11/26
1 | 2013/11/27
And my query:
SELECT
q.id_quest,
q.desc_quest,
COUNT(a.id_quest) as total_answer -- count total answer by question
FROM tb_question q
INNER JOIN tb_answer a
ON q.id_quest = a.id_quest;
Result:
ID_QUEST | DESC_QUEST | TOTAL_ANSWER
1 | How do you do...? | 3
How could it do to return also question id = 2 with 0 count ?
Expected result:
ID_QUEST | DESC_QUEST | TOTAL_ANSWER
1 | How do you do...? | 3
2 | How are you...? | 0
http://sqlfiddle.com/#!2/3bfe7/1
Two problems:
You have to use an outer join to get questions with no answers.
You left out the GROUP BY clause.
SELECT
q.id_quest,
q.desc_quest,
COUNT(a.id_quest) as total_answer
FROM tb_question q
LEFT OUTER JOIN tb_answer a ON q.id_quest = a.id_quest
GROUP BY q.id_quest
DEMO
dont use inner join to select all idquest, inner join to produce subset of table
SELECT tbq.id_quest,tbq.desc_quest,COUNT(tba.id_quest)
FROM tb_question tbq
LEFT OUTER JOIN tb_answer tba ON tba.id_uest=tbq.id_quest
GROUP BY tbq.id_quest
ORDER BY tbq.id_quest

Using SUM to count three tables with relevant records

I'm trying to use the SUM function to count rows from 3 tables, which is however, not working effectively since when the total_files and total_notes are returned, they both are the same when there is at least one file and then total_files will take the same value as total_notes which I don't understand why it's doing that.
It should count the number of rows which is relevant to each record that will get return as a record list with a count of total files, total notes and total contacts assigned to the record per record row (the data of files, notes and contacts do not get displayed only counted).
My query is shown below:
SELECT rec.street_number,
rec.street_name,
rec.city,
rec.state,
rec.country,
rec.latitude,
rec.longitude,
LEFT(rec.description, 250) AS description,
usr.username,
usr.full_name,
ppl.person_id,
ppl.first_name,
ppl.last_name,
SUM(IF(rlk.record_id = rec.record_id, 1, 0)) AS total_contacts,
SUM(IF(files.record_id = rec.record_id, 1, 0)) AS total_files,
SUM(IF(notes.record_id = rec.record_id, 1, 0)) AS total_notes,
(
SELECT COUNT(DISTINCT rec.record_id)
FROM records rec
WHERE rec.marked_delete = 0 AND rec.is_archive = 0
) AS total_records
FROM
(
records rec
INNER JOIN members usr ON rec.user_id = usr.user_id
LEFT OUTER JOIN record_links rlk ON rec.record_id = rlk.record_id
LEFT OUTER JOIN people ppl ON ppl.person_id = rlk.person_id AND rlk.record_id = rec.record_id
LEFT OUTER JOIN files files ON files.record_id = rec.record_id
LEFT OUTER JOIN notes notes ON notes.record_id = rec.record_id
)
WHERE rec.marked_delete = 0 AND rec.is_archive = 0
GROUP BY rec.record_id
ORDER BY rec.submit_date DESC
LIMIT 0, 25
Basically as you can see there is three SUM which will count relevant rows that comes from those tables, but I seriously don't understand how total_files would be taking the same value as total_notes is there something wrong I'm doing here?
It's because rec is joined to both notes and files.
Suppose record 1 has 2 notes and 1 file, record 2 has two note and two files, and record 3 has a note but no files.
Then the table rec LEFT OUTER JOIN files ... LEFT OUTER JOIN notes will look like this:
+-----------+---------+---------+
| record_id | file_id | note_id |
+-----------+---------+---------+
| 1 | 1 | 1 |
| 1 | 2 | 1 |
| 2 | 3 | 2 |
| 2 | 3 | 3 |
| 2 | 4 | 2 |
| 2 | 4 | 3 |
| 3 | NULL | 4 |
+-----------+---------+---------+
Note how every file_id gets joined to every note_id (within the same record_id). Also, since you have SUM(IF(files.record_id = rec.record_id,1,0)) and the join condition is files.record_id = rec.record_id, you are actually counting COUNT(files)*COUNT(notes) per record_id.
I'd recommend you instead COUNT(DISTINCT files.id) and COUNT(DISTINCT records.id). The column in the COUNT would be your primary key on files/notes, not files.record_id:
SELECT rec.record_id,
COUNT(DISTINCT files.id) AS total_files,
COUNT(DISTINCT notes.id) AS total_notes
FROM rec
-- note: LEFT OUTER JOIN is the same as LEFT JOIN in MySQL
LEFT JOIN files ON files.record_id=rec.record_id
LEFT JOIN notes ON notes.record_id=rec.record_id
GROUP BY record_id
+-----------+-------------+-------------+
| record_id | total_files | total_notes |
+-----------+-------------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 0 | 1 |
+-----------+-------------+-------------+
Of course, adjust to your query as necessary (add in those extra columns/joins).