MySQL select and sum from multiple table without duplicate it - mysql

i have 3 tables :
table1
code(Primary key) | name | quantity
B001 | sand | 50
B002 | nail | 100
B003 | paint | 10
=======
table2
code | qty_out
B001 | 2
B001 | 1
B001 | 20
B002 | 10
B002 | 30
=======
table3
code | qty_in
B001 | 1
B001 | 5
B002 | 5
B002 | 10
=======
Result that I want is:
table1
code | name | quantity | Out | In | total
B001 | sand | 50 | 23 | 6 | 33
B002 | nail | 100 | 40 | 15 | 75
B003 | paint | 10 | null/0 | null/0 | 10
I used this query :
SELECT table1.code, table1.name, table1.quantity, sum(table2.qty_out ) AS 'Out', sum( table3.qty_in ) AS 'In'
FROM table1
LEFT JOIN table2 ON table2.code = table1.code
LEFT JOIN table3 ON table3.code = table1.code
GROUP BY table1.code
ORDER BY table1.code ASC
In that query I get result like this...code B001 out 46 and in 18, code B002 out 80 and in 30, code B003 out null and in null
How to fix this?

use this query
select t.code,t.name,t.quantity,t.out,t.in,(t.out+t.in) as total
from (
SELECT table1.code, table1.name, table1.quantity,
( select sum(table2.qty_out)
from table2
where table1.code=table2.code ) as out,
( select sum(table3.qty_in)
from table3
where table3.code=table1.code ) as in
FROM table1
) as t

Using a subquery, a UNION clause and GROUPping, I built the following query :
SELECT
p.code,
p.name,
-- Using IFNULL to handle products without stock variation
IFNULL(SUM(q.q_in), 0) AS total_in,
IFNULL(SUM(q.q_out), 0) AS total_out,
-- Compute the new stock level
p.qty + IFNULL(SUM(q.q_in), 0) - IFNULL(SUM(q.q_out), 0) AS qty
FROM (
-- UNION (= concatenate) prod_in and prod_out tables
SELECT
product,
qty AS q_in,
0 AS q_out -- Enforce schema (otherwise, q_out is dropped)
FROM prod_in
UNION
SELECT
product,
0 AS q_in,
qty AS q_out
FROM prod_out
) AS q
-- Using a RIGHT join to show products without stock variations
RIGHT JOIN products AS p
ON p.code = q.product
-- Group by id to get the summarized view
GROUP BY q.product
Here's the query in a working SQLfiddle with your sample data

Related

How to get max value of a grouped counted variable in MySQL

I have a MySQL table like this;
recordID| netcall | sign | activity | netid
1 | group1 | wa1 | 1 | 20
2 | group2 | wa2 | 2 | 30
3 | group1 | wa2 | 1 | 20
4 | group2 | wa3 | 2 | 30
5 | group1 | wa1 | 1 | 40
6 | group3 | wa4 | 3 | 50
7 | group3 | wa4 | 3 | 50
8 | group1 | wa2 | 1 | 40
9 | group1 | wa1 | 1 | 40
10 | group2 | wa4 | 2 | 60
What I need from that is:
Netcall | count | activity | netid
Group1 | 3 | 1 | 40
Group2 | 2 | 2 | 30
Group3 | 2 | 3 | 50
I thought I could;
SELECT MAX(xx.mycount) AS MAXcount
FROM (SELECT COUNT(tt.sign) AS mycount ,tt.activity
FROM NetLog tt
WHERE ID <> 0
GROUP BY netcall) xx
But this only brings up the grand total not broken down by netcall. I don't see an example of this question but I'm sure there is one, I'm just asking it wrong.
Your example and desire output are too basic, you should try to expand so include more cases.
Right now you can get the desire output with:
SELECT `netcall`, COUNT(*) as `total`, MAX(`activity`) as `activity`
FROM t
GROUP BY `netcall`;
My guess is you can have different activities for group so you need multiples steps
Calculate the COUNT() for GROUP BY netcall, activity I call it q
Then see what is the MAX(total) for each netcall I call it p
Now you reuse q as o you have all the count, so just select the one with the max count.
SQL DEMO
SELECT o.`netcall`, o.total, o.`activity`
FROM (
SELECT `netcall`, COUNT(*) `total`, `activity`
FROM t
GROUP BY `netcall`, `activity`
) o
JOIN (
SELECT `netcall`, MAX(`total`) as `total`
FROM (
SELECT `netcall`, COUNT(*) `total`
FROM t
GROUP BY `netcall`, `activity`
) q
GROUP BY `netcall`
) p
ON o.`netcall` = p.`netcall`
AND o.`total` = p.`total`
With MySQL v8+ you can use cte and window function to simplify a little bit
with group_count as (
SELECT `netcall`, COUNT(*) as total, `activity`
FROM t
GROUP BY `netcall`, `activity`
), group_sort as (
SELECT `netcall`, total, `activity`,
RANK() OVER (PARTITION BY `netcall`, `activity` ORDER BY total DESC) as rnk
FROM group_count
)
SELECT *
FROM group_sort
WHERE rnk = 1
This question is asked (and answered) every day on SO; it even has its own chapter in the MySQL manual, but anyway...
SELECT a.netcall
, b.total
, a.activity
FROM netlog a
JOIN
( SELECT netcall
, MAX(record_id) record_id
, COUNT(*) total
FROM netlog
GROUP
BY netcall
) b
ON b.netcall = a.netcall
AND b.record_id = a.record_id
SELECT k.netcall, k.netID, MAX(k.logins) highest,
AVG(k.logins) average, netDate, activity
FROM
(SELECT netID, netcall, COUNT(*) logins, DATE(`logdate`) as netDate, activity
FROM NetLog
WHERE netID <> 0 AND status = 1
AND netcall <> '0' AND netcall <> ''
GROUP BY netcall, netID) k
GROUP BY netcall
ORDER BY highest DESC
Resulted in:
Net Call Highest Average Net ID Sub Net Of... ICS
214 309 Map Date Activity
MESN 65 41.5294 339 214 309 MAP 2017-09-03 MESN
W0KCN 34 14.9597 1 214 309 MAP 2016-03-15 KCNARES Weekly 2m Voice Net
W0ERH 31 31.0000 883 214 309 MAP 2018-10-12 Johnson Co. Radio Amateurs Club Meeting Net
KCABARC 29 22.3333 57 214 309 MAP 2016-10-10 KCA Blind Amateurs Weekly 2m Voice Net
....

How to join and give a default if a value is in one table but not another?

I am using MySQL, and I'm a newbie!
Hope you guys here can help me with a SQL question.
Say I have 2 tables, and I want to a simple join.
Table 1:
id | service_id | user_number
----------------------------------------------------------------------
0 | 1001 | 10
1 | 1002 | 20
2 | 1004 | 40
Table 2:
id | service_id | error_number
----------------------------------------------------------------------
0 | 1001 | 1000
1 | 1003 | 3000
2 | 1004 | 4000
I want to do a join on service_id and have default value of user_number and error_number to be 0 if it does not exist.
So:
id | service_id | user_number | error_number
----------------------------------------------------------------------
0 | 1001 | 10 | 1000
1 | 1002 | 20 | 0
3 | 1003 | 0 | 3000
2 | 1004 | 40 | 4000
I tried some queries, but they kept giving me null instead of 0.
Thanks a lot.
Here you should use union first, then do aggregation:
select t.`service_id`, sum(t.`user_number`) as `user_number`, sum(t.`error_number`) as `error_number`
from (
select `service_id`, `user_number`, 0 as `error_number` from t1
union
select `service_id`, 0 as `user_number`, `error_number` from t2
) t
group by `service_id`
demo here.
You can try this one, mate:
SELECT
t1.id,
t1.service_id,
COALESCE(tb1.user_number, 0) `user_number`,
COALESCE(tb2.error_number, 0) `error_number`
FROM
(
SELECT id, service_id
FROM table1
UNION
SELECT id, service_id
FROM table2
) t1
LEFT JOIN table1 tb1 ON tb1.service_id = t1.service_id
LEFT JOIN table2 tb2 ON tb2.service_id = t1.service_id;
Try this:
select COALESCE(t1_service,t2_service ) as service_id, COALESCE(user_number,0) as user_number , COALESCE(error_number,0) as error_number
from (
select t1.service_id as t1_service , t1.user_number , t2.error_number, t2.service_id as t2_service
from table_1 t1
LEFT OUTER JOIN table_2 t2
on t1.service = t2.service
union
select t1.service_id as t1_service , t1.user_number , t2.error_number, t2.service_id as t2_service
from table_1 t1
Right OUTER JOIN table_2 t2
on t1.service = t2.service
)z1
order by service_id

nested query & transaction

Update #1: query gives me syntax error on Left Join line (running the query within the left join independently works perfectly though)
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance'
FROM MyTable b1
JOIN CustomerInfoTable c on c.id = b1.company_id
#Filter for Clients of particular brand, package and active status
where c.brand_id = 2 and c.status = 2 and c.package_id = 3
LEFT JOIN
(
SELECT b2.company_id, sum(b2.debit) as 'Current_Usage'
FROM MyTable b2
WHERE year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
)
b3 on b3.company_id = b1.company_id
group by b1.company_id;
Original Post:
I keep track of debits and credits in the same table. The table has the following schema:
| company_id | timestamp | credit | debit |
| 10 | MAY-25 | 100 | 000 |
| 11 | MAY-25 | 000 | 054 |
| 10 | MAY-28 | 000 | 040 |
| 12 | JUN-01 | 100 | 000 |
| 10 | JUN-25 | 150 | 000 |
| 10 | JUN-25 | 000 | 025 |
As my result, I want to to see:
| Grouped by: company_id | Balance* | Current_Usage (in June) |
| 10 | 185 | 25 |
| 12 | 100 | 0 |
| 11 | -54 | 0 |
Balance: Calculated by (sum(credit) - sum(debits))* - timestamp does not matter
Current_Usage: Calculated by sum(debits) - but only for debits in JUN.
The problem: If I filter by JUN timestamp right away, it does not calculate the balance of all time but only the balance of any transactions in June.
How can I calculate the current usage by month but the balance on all transactions in the table. I have everything working, except that it filters only the JUN results into the current usage calculation in my code:
SELECT b.company_id, ((sum(b.credit)-sum(b.debit))/1024/1024/1024/1024) as 'BW_remaining', sum(b.debit/1024/1024/1024/1024/28*30) as 'Usage_per_month'
FROM mytable b
#How to filter this only for the current_usage calculation?
WHERE month(a.timestamp) = 'JUN' and a.credit = 0
#Group by company in order to sum all entries for balance
group by b.company_id
order by b.balance desc;
what you will need here is a join with sub query which will filter based on month.
SELECT T1.company_id,
((sum(T1.credit)-sum(T1.debit))/1024/1024/1024/1024) as 'BW_remaining',
MAX(T3.DEBIT_PER_MONTH)
FROM MYTABLE T1
LEFT JOIN
(
SELECT T2.company_id, SUM(T2.debit) T3.DEBIT_PER_MONTH
FROM MYTABLE T2
WHERE month(T2.timestamp) = 'JUN'
GROUP BY T2.company_id
)
T3 ON T1.company_id-T3.company_id
GROUP BY T1.company_id
I havn't tested the query. The point here i am trying to make is how you can join your existing query to get usage per month.
alright, thanks to #Kshitij I got it working. In case somebody else is running into the same issue, this is how I solved it:
SELECT b1.company_id, ((sum(b1.credit)-sum(b1.debit)) as 'Balance',
(
SELECT sum(b2.debit)
FROM MYTABLE b2
WHERE b2.company_id = b1.company_id and year(b2.timestamp) = '2012' and month(b2.timestamp) = '06'
GROUP BY b2.company_id
) AS 'Usage_June'
FROM MYTABLE b1
#Group by company in order to add sum of all zones the company is using
group by b1.company_id
order by Usage_June desc;

MySQL: Join a table to itself

I have a table of preferences, called "txp_prefs". I would like to return multiple preferences into a single row; the reason I prefer this to a simple concatenation is that I'm using a plugin in textpattern which can process the single row.
Here is the testing data I have:
------------------------------------------------
|Id | event | name |value |
------------------------------------------------
| 1 | season | season_start | 12/10/2011 |
-----------------------------------------------
| 2 | season | season_end | 29/10/2011 |
------------------------------------------------
| 3 | season | season_countdown | 7 |
------------------------------------------------
| 4 | another | test1 | result1 |
------------------------------------------------
| 3 | | test2 | result2 |
------------------------------------------------
The final result I would like to get is:
----------------------------------------------------------
|event | season_start | season_end | season_countdown |
----------------------------------------------------------
|season | 12/10/2011 | 29/10/2011 | 7 |
----------------------------------------------------------
I can (obviously) create the separate queries to get each result independently; for example
SELECT t1.event, t1.val AS season_start FROM txp_prefs t1 WHERE t1.event="season" AND t1.name="season_start" (to get the season_start)
SELECT t2.event, t2.val AS season_end FROM txp_prefs t2 WHERE t2.event="season" AND t2.name="season_end" (to get the season_end)
But I get errors when I try to join the two together, eg like this:
SELECT t1.event, t1.val AS season_start FROM txp_prefs t1 WHERE t1.event="season" AND t1.name="season_start"
LEFT JOIN
(SELECT t2.event, t2.val AS season_end FROM txp_prefs t2 WHERE t2.event="season" AND t2.name="season_end") t3
ON t1.event=t3.event
The error messages says it is something to do with the join (which I guessed anyway - the two individual queries work.
Any ideas? I have recently figured through joining different tables together, so I assume it is possible to join a table to itself.
Based on the structure given you can use
SELECT
MAX(CASE WHEN name = 'season_start' THEN value END) AS season_start,
MAX(CASE WHEN name = 'season_end' THEN value END) AS season_end,
MAX(CASE WHEN name = 'season_countdown' THEN value END) AS season_countdown
FROM txp_prefs
WHERE event='season'
You can do this by pivoiting. Asper my past project I demostrate you in following query hope will be useful to you.
My table transaction is having following fields
NAME VARCHAR2(10)
branch_code NUMBER(4)
Ruppes NUMBER(4)
SQL> select * from transaction;
NAME branch_code Ruppes
---------- ---------- ----------
Hemang 2602 1000
Hemang 2603 2000
Hemang 2400 3000
Yash 2602 1500
Yash 2603 1200
Yash 2400 1340
Krupesh 2602 1250
Krupesh 2603 2323
Krupesh 2400 8700
9 rows selected.
Now pivoting.
SQL> select branch_code,
2 max( decode( name, 'Hemang', Ruppes, null ) ) "Hemang",
3 max( decode( name, 'Yash', Ruppes, null ) ) "Yash",
4 max( decode( name, 'Krupesh', Ruppes, null ) ) "Krupesh"
5 from
6 (
7 select name, branch_code, Ruppes
8 from transaction
9 )
10 group by branch_code ;
branch_code Hemang Yash Krupesh
---------- ---------- ---------- ----------
2602 1000 1500 1250
2603 2000 1200 2323
2400 3000 1340 8700
select you are looking for is:
SELECT distinct
t0.event,
t1.val AS season_start ,
t2.val as seasson_end,
t3.val as season_countdown
FROM
txp_prefs t0
left outer join
txp_prefs t1
on ( t1.event=t0.event AND t1.name="season_start" )
left outer join
txp_prefs t2
on ( t2.event=t0.event AND t2.name="season_end" )
left outer join
txp_prefs t3
on ( t3.event=t0.event AND t3.name="season_countdown" )
WHERE
t0.event="season"
(the standard way to get only one row is 'distintc' reserved word. Another solution is append 'LIMIT 1' to query, but this is MySQL dependant)
are you sure that your database is right normalized?
see you.

Getting unique values in sql server

I have a table say :
id| AccID | Subject | Date
1 | 103 | Open HOuse 1 | 11/24/2011 9:00:00 AM
2 | 103 | Open HOuse 2 | 11/25/2011 10:00:00 AM
3 | 72 | Open House 3 | 11/26/2011 1:10:28 AM
4 | 82 | OPen House 4 | 11/27/2011 5:00:29 PM
5 | 82 | OPen House 5 | 11/22/2011 5:00:29 PM
From the above table, i need all the unique values for the Accid. But say, if there are two or more columns with the same Accid, then i need the one which has the smaller date (among the columns which have the same Accid)
So, from the above table, the o/p should be :
1
3
5
Can any1 please help me in this ? Thanks
SELECT t1.*
FROM [MyTable] t1
INNER JOIN
(
SELECT AccID, MIN(Date) Date
FROM [MyTable]
GROUP BY AccID
) t2 ON t1.AccID = t2.AccID AND t1.Date = t2.Date
More than just the AccID but...
WITH SEL
AS
(
SELECT AccID, MIN(DATE)
FROM table
GROUP BY AccID
)
SELECT table.*
FROM table
JOIN SEL ON SEL.AccID = table.AccID