Connecting two mySQL tables and and summarising with unique values - mysql

I've got two mySQL tables, Table A and B. I need to get an output like in Table 3.
Below mentioned is the code I tried with Full Join and does not give me the intended result. Much appreciate your help..
SELECT DISTINCT(Table_A.Code) as 'Code', SUM(Table_A.Qty_On_Hand) as 'On Hand Qty', SUM(Table_B.Counted_Qty) as 'Counted Qty'
FULL JOIN Table_B ON Table_A.Code = Table_B.Code
FROM Table_A
Table A
Code
On Hand Qty
A
20
B
10
B
20
B
50
C
60
Table B
Code
Counted Qty
A
10
B
0
C
30
B
0
C
10
Out put required:
Code
On Hand Qty
Counted Qty
A
20
10
B
80
0
C
60
40

You need to use GROUP BY Table_A.Code, not DISTINCT.
SELECT a.Code, SUM(a.Qty_On_Hand) AS `On Hand Qty`, b.`Counted Qty`
FROM Table_A as a
JOIN (
SELECT Code, SUM(Counted_Qty) AS `Counted Qty`
FROM Table_B
GROUP BY Code
) AS b ON a.Code = b.Code
GROUP BY a.Code
You need to do one of the SUMs in a subquery, otherwise you'll multiply its sums by the number of rows in the other table. See Join tables with SUM issue in MYSQL.

Related

MySQL compatibility or similarity ranking queries

G'day, I'm trying to develop a way to query compatibility or similarity between values and failing. It's not a highest or lowest AVG rating but rather smallest difference between values over a number or rows. So if structure is something like the following where RANK is the "rating" by the USER.
USER ITEM RANK
A x 5
B x 6
C x 2
A y 2
B y 3
C y 8
A z 7
B z 4
C z 4
At the end I'd like to be able to sort across the data like:
User A vs User B have avg rating difference of 3
User A vs User C have avg rating difference of 4
User B vs User C have avg rating difference of 5
My only thought so far is to build a temp table (huge) with every permutation:
col1 col2 dif item
A B 1 x
A C 3 x
etc...
And then SUM with a GROUP. But that still doesn't deal properly with occasions where User A and C match closer on some items and have greater diff on other items to outweigh the initial closeness. Any direction anyone can give?
Thanks!
This is a mysql 5.5 db so I'm missing any CTE or the like on query structure.
could be using a self join
select a.user, b.user, abs(a.rank - b.rank) diff_rank, a.item
from my_table a
inner join my_table b on a.item = b.item and a.user <> b.user
order by item, diff_rank asc
for avoid duplicated value you can use distinct
select distinct a.user, b.user, abs(a.rank - b.rank) diff_rank, a.item
from my_table a
inner join my_table b on a.item = b.item and a.user <> b.user
order by item, diff_rank asc
and for obtain the users with the lowest diff firts you can change the order by
select distinct a.user, b.user, abs(a.rank - b.rank) diff_rank, a.item
from my_table a
inner join my_table b on a.item = b.item and a.user <> b.user
order by diff_rank asc

JOIN vs "just" SELECT

I have the next tables:
date Income AccIncome
--------------------------------
2016-10-1 10 10
2017-11-1 20 30
date Qty AccQty
--------------------------------
2016-10-1 2 2
2017-11-1 4 6
date Ava AccAva
--------------------------------
2016-10-1 3 3
2017-11-1 4 7
I need to obtain:
date Income AccIncome Qty AccQty Ava AccAva
------------------------------------------------------
2016-10-1 10 10 2 2 3 3
2017-11-1 20 30 4 6 4 7
I could use a select using all these tables but how could this be done with a JOIN? Could the JOIN be much faster than using just a SELECT over all these tables picking up just the fields I need?
You can use inner join on date if the joining values in rows always match
select a.date, a.income, a.AccIncome, b.Qty, b.AccQty, c.Ava, c.AccAva
from table1 a
inner join table2 b on a.date= b.date
inner join table3 c on a.date = c.date
or left join if can not match
select a.date, a.income, a.AccIncome, b.Qty, b.AccQty, c.Ava, c.AccAva
from table1 a
left join table2 b on a.date= b.date
left join table3 c on a.date = c.date
if you use only a select withou join and on condtion you obtain a cartesia product of all the rows .. so in your case instead of two row as result .. you get 8 rows
and the inner/left join is normally much more faster that a cross join ( a select over all table) because work on reduced set o rows.. for help the join performance is useful a proper indexinig of the rows
the on clause in join and the same condition in where clause do the same work .. is only a diffrent sintax in the first case you have an explict join sintax more clear to read in the secondo you have an inplicit join .

How to query two differents mysql tables and compare results

I have two Mysql queries:
1:
select TblC.name,
SUM(TblC.total) as Sum
from TblC
left join TblCli on TblC.id_cli = TblCli.id
group by TblCli.name asc
The result is
NAME SUM
john 1000
peter 500
Alicia 300
2:
select TblCli.name,
SUM(TblRec.total) as Pay
from TblRec
left join TblCli on TblRec.id_cli = TblCli.id
group by TblCli.name asc
The result is
NAME Pay
john 500
peter 100
There are two different tables with no direct relation
I need to join these two queries and get a result like this:
NAME SUM PAY Difference
john 1000 500 500
peter 500 100 400
Alicia 300 0 300
How can I perform that?
The following should work. Demo with your data: http://sqlfiddle.com/#!9/ba6264/6
I highly recommend you do joins by TblCli.id instead of TblCli.name
select A.name, sum , IFNULL(pay,0) as pay, (sum - IFNULL(pay,0)) Difference FROM
(select TblC.name,
SUM(TblC.total) as Sum
from TblC
left join TblCli on TblC.id_cli = TblCli.id
group by TblCli.name) A
LEFT JOIN
(select TblCli.name,
SUM(TblRec.total) as Pay
from TblRec
left join TblCli on TblRec.id_cli = TblCli.id
group by TblCli.name) B
ON A.name = B.name;

3 Table Join with SUM and GROUP BY not working

I have three tables that I'm working with.
AccountingLine - Holds the generic account details
Budget - Holds the budget data for each AccountingLine (Many rows per AccountingLine)
Actual - Holds the actual cost data for each AccountingLine (Many rows per AccountingLine)
I'm trying to get the results in a single query which will return ALL ROWS from the AccountingLine table, and SUM the Amounts for each AccountingLine from the Budget and Actuals table.
Using the SQL below, the SUM isn't working for the Budget or Actual data. If I remove one of the joins and one of the SUM functions then it calculates correctly for the single joined table. Very strange... anyone run across this with multiple SUM functions on three or more tables in MySQL?
SELECT A.*, SUM(B.`amount`) AS BudgetAmount, SUM(ACT.`amount`) as ActualAmount
FROM accounting_line A
LEFT JOIN budget B ON B.accounting_line_id = A.accounting_line_id
LEFT JOIN actual ACT ON ACT.accounting_line_id = A.accounting_line_id
GROUP BY A.`accounting_line_id`
By issuing the statement above, I'd expect to see the accounting_line fields, the SUM of the Budget amounts for each accounting_line and the SUM of the Actual amounts for each accounting_line.
I've searched all over and can't find an instance of multiple SUM functions. Thanks so much for any advice.
Josh
Table Data is below:
Table: AccountingLine
act_line_id department
----------------------------------
1 Sales
2 HumanResources
Table: Budget
budget_id actg_line_id amount
----------------------------------------------
1 1 3500.00
2 2 5000.00
3 2 15000.00
Table: Actual
actual_id actg_line_id amount
----------------------------------------------
1 1 1000.00
2 2 500.00
3 2 9000.00
A join repeats each matching row in the other table. So if you have 3 rows in three tables and join them together, you end up with 9 rows. If you sum, each sum from the second and third table is 3x too high.
One solution is to sum in a subquery, so that the join only finds one row:
SELECT A.*
, B.SumAmount as BudgetAmount
, ACT.SumAmount as ActualAmount
FROM accounting_line A
LEFT JOIN
(
select accounting_line_id
, sum(amount) as SumAmount
from budget
group by
accounting_line_id
) as B
ON B.accounting_line_id = A.accounting_line_id
LEFT JOIN
(
select accounting_line_id
, sum(amount) as SumAmount
from actual
group by
accounting_line_id
) as ACT
ON ACT.accounting_line_id = A.accounting_line_id
try this modified one, calculate it's totals on a subquery
SELECT a.*, b.totalBudget, c.totalActual
FROM AccountingLine a LEFT JOIN
(
SELECT actg_line_id, SUM(amount) totalBudget
FROM Budget
GROUP BY actg_line_id
) b on a.act_line_id = b.actg_line_id
LEFT JOIN
(
SELECT actg_line_id, SUM(amount) totalActual
FROM Actual
GROUP BY actg_line_id
) c on a.act_line_id = c.actg_line_id
SQLFiddle Demo
Try this
Select A.* ,SUM(B.Amount) As BudgetAmount,SUM(Act.Amount) As ActualAmount
from AccountingLine A
INNER JOIN Budget B
ON B.budget_id = A.actg_line_id
INNER JOIN Actual Act
ON Act.actual_id = A.accounting_line_id
Grounp By A.accounting_line_id

Find number of joins by a reference table

Apologies if the title is ambiguous, but I could not figure out a good way to title this problem.
In my database, I have a table J that joins tables A and B. That is to say, J has columns a_id, and b_id that hold the id of entries in A and B respectively. B also has a 'code' column in it; for the sake of example, let's say there are three entries with codes of 'CC', 'DD', and 'EE'.
Now, I want to write a query that lists how many A's have each type of code in B (how many A's have 'CC', how many have 'DD', and how many have 'EE').
I write that query as follows, and get the following output (fabricated data, of course -- sorted by alphabetical code order):
SELECT b.CODE as code, COUNT(*) AS COUNT FROM a, b, j
WHERE j.a_id = a.id AND j.b_id = b.id
GROUP BY b.CODE ORDER BY b.CODE
code | count
==============
CC | 5
DD | 10
EE | 2
The problem occurs when I add in a new record to B, say with code 'FF'. Now at this point, I have no entries in J that point to code 'FF'. So in the output, I want to include 'FF', but show that the count is 0 (no A's are joined to 'FF').
code | count
==============
CC | 5
DD | 10
EE | 2
FF | 0
However, with my current query, it doesn't do this and in fact leaves out all codes where the resulting count is 0.
Can any query masters out there help me to alter my query to include the counts for all codes, whether they are 0 or not? It would be greatly appreciated.
Ian
You'll need to use a LEFT JOIN here to do this. The LEFT JOIN will give you all rows from table b, whether or not they have matching rows in table j.
SELECT b.CODE as code, COUNT(a.id) AS COUNT
FROM b
LEFT JOIN j
INNER JOIN a
ON j.a_id = a.id
ON j.b_id = b.id
GROUP BY b.CODE
ORDER BY b.CODE
You need to use a LEFT JOIN:
SELECT b.CODE as code, COUNT(a.id) AS a_count
FROM b LEFT JOIN (j JOIN a ON j.a_id = a.id) ON j.b_id = b.id
GROUP BY b.CODE ASC