I have two table L with columns (Code, Qtr, Fy, Limit) and R with (Code, Qtr,Fy,Limit). I want to get sum of limit of left and right table group by code, Qtr an Fy
The following query runs with no error but gives wrong output, can anyone help me in getting right output. IF I use only one table it works fine. I guess problem is with join
select L.Code, L. Qtr, L.FY, sum(L.limit),sum(R.Limit)
from tbl L,tbl R Where
L.Code=R.Code AND
L.Qtr=R.Qtr AND
L.FY=R.FY
group by L.Code,L.Qtr,L.FY
Sample Data ( the table contains other column as well but here i m keeping only selected)
Tbl L
Code Qtr, Fy Limit
001 1 70 200
001 1 70 700
001 2 70 500
001 2 70 300
Table R
Code Qtr Fy Limit
001 1 70 1000
001 1 70 200
001 2 70 50
001 2 70 125
Result
Code Qtr Fy Sum(l.Limit) sum(R.Limit)
001 1 70 900 1200
001 2 70 800 175
I m Using Mysql
Try this query:
select code, qtr, fy, sum(lsum), sum(rsum)
from (
select L.Code, L.Qtr, L.FY, L.limit as lsum, 0 as rsum
from L
union all
select R.Code, R.Qtr, R.FY, 0 as lsum, R.limit as rsum
from R) as combined
group by code, qtr, fy
Using join in this case would be a wrong idea because it will create multiple records (one for each match between L and R) and then when you do a sum you get incorrect results.
The problem is indeed the join - specifically, you're running into problems because you are using a GROUP BY after the join, when the join criteria results in non-unique rows. Usually, the way to solve this is to group before the join:
SELECT L.code, L.qtr, L.fy, L.lim as L_lim, R.lim as R_lim
FROM (SELECT code, qtr, fy, SUM(lim) as lim
FROM L
GROUP BY code, qtr, fy) L
JOIN (SELECT code, qtr, fy, SUM(lim) as lim
FROM R
GROUP BY code, qtr, fy) R
ON R.code = L.code
AND R.qtr = L.qtr
AND R.fy = L.fy
(have a working SQL Fiddle example)
Note that this will only show results for rows that are in both tables. Also, LIMIT is a reserved word (in MySQL and some other RDBMSs), so you're better off avoiding that for a column name.
Related
I just want to display column fields horizontally but also putting a condition to it. Display zero if it has not met the condition.
Example problem: Find the PAYCODE 912 and 686 and display the amount, if not available, display 0
my_table
EMPLOYEE
PAYCODE
AMOUNT
1
912
1
1
123
3
2
912
5
2
686
7
3
111
4
Output must be:
EMPLOYEE
AMOUNT
1
1,0
2
5,7
3
0,0
My code so far:
SELECT
EMPLOYEE,
GROUP_CONCAT(DISTINCT CONCAT(
IF(PAYCODE = '912', AMOUNT, '0'),
IF(PAYCODE = '686', AMOUNT, '0'))
SEPARATOR',') as AMOUNT
FROM
my_table
Note: There are no duplicate paycodes on a similar employee. e.g. two 912 paycodes
I'm thinking a cross join approach should work here:
SELECT e.EMPLOYEE,
GROUP_CONCAT(COALESCE(t.AMOUNT, 0) ORDER BY e.PAYMENTTYPE DESC) AS AMOUNT
FROM (SELECT DISTINCT EMPLOYEE FROM my_table) e
CROSS JOIN (SELECT '912' AS PAYMENTTYPE UNION ALL SELECT '686') p
LEFT JOIN my_table t
ON t.EMPLOYEE = e.EMPLOYEE AND
t.PAYMENTTYPE = p.PAYMENTTYPE
GROUP BY e.EMPLOYEE;
The cross join between the e and p subqueries generates all employee/payment type combinations of interest (only types 912 and 686). We then left join to your table to bring in the amounts, which if are missing we report 0 instead.
Been trying to figure this out for a couple hours and hoping for some expert assistance:
I have a single Mysql table with data such as:
Date version amount
2021-03-01 A 100
2021-03-02 A 35
2021-03-02 B 80
2021-03-03 A 7
2021-03-03 B 90
2021-03-03 C 3
2021-03-03 A 8
2021-03-04 B 15
2021-03-04 C 90
2021-03-04 B 10
And trying to get output for each version for every day, with amount populated as '0' for null;
Result:
Date version SUM(amount)
2021-03-01 A 100
2021-03-01 B 0
2021-03-01 c 0
2021-03-02 A 35
2021-03-02 B 80
2021-03-02 C 0
2021-03-03 A 15
2021-03-03 B 90
2021-03-03 C 3
2021-03-04 A 0
2021-03-04 B 25
2021-03-04 C 90
I tried various 'JOIN', 'LEFT JOIN' and 'CROSS JOIN' permutations without success.
SELECT distinct c1.date, c2.version
FROM crash_log c1
LEFT OUTER JOIN crash_log c2 ON c1.date = c2.date
GROUP BY c1.date, c2.version
(not even messing with the SUM, just trying to get all the rows with this one)
For now, I have a script that does this by brute force: gets DISTINCT date, then get DISTINCT version, then do a nested loop and build an array for each combination. One trouble is it's not scalable and seems the web connection is timing out before the process finishes on a large set.
I'm thinking there's one (semi-?) efficient query that can do this, but I haven't been able to figure it out.
Write subqueries to get all the dates and versions. Cross join these to get every combination.
Then left join that with the table to get either the actual value or default to 0 when NULL.
SELECT d.date, v.version, IFNULL(c.sum, 0) AS sum
FROM (
SELECT DISTINCT date
FROM crash_log) AS d
CROSS JOIN (
SELECT DISTINCT version
FROM crash_log) AS v
LEFT JOIN (
SELECT date, version, SUM(amount) AS sum
FROM crash_log
GROUP BY date, version) AS c ON d.date = c.date AND v.version = c.version
ORDER BY d.date, v.version
Just like your script, but in SQL.
Cross join the distinct dates to the distinct versions and left join to the table and finally aggregation:
SELECT d.Date, v.version, COALESCE(SUM(t.amount), 0) sum_amount
FROM (SELECT DISTINCT Date FROM tablename) d
CROSS JOIN (SELECT DISTINCT version FROM tablename) v
LEFT JOIN tablename t
ON t.Date = d.Date AND t.version = v.version
GROUP BY d.Date, v.version
I am trying to get the records where avg is greater than 81, I noticed I can't use a simple where avg(score) > 80
But using a Having statement is problematic as well as it does not consider where the individual records average is greater than 80, but it considers the group average. Is there an alternative?
In general, if we want to return aggregates (SUM,AVG) and also return detail that makes up the aggregate, we typically use two SELECT
As a rudimentary example, consider a table of "test_score"
test_id student_id score
------- ---------- -----
101 6 90
101 7 71
101 8 88
222 6 93
222 7 78
222 8 81
We can calculate the average score for each test, with a SELECT ... GROUP BY query.
SELECT r.test_id AS test_id
, AVG(r.score) AS avg_score
, MAX(r.score) AS high_score
FROM test_score r
GROUP
BY r.test_id
We expect that to return a resultset like this:
test_id avg_score
------- ---------
101 83
222 84
We can use that query as an inline view i.e. we wrap it in parens and reference it like a table in the FROM clause of another SELECT.
As a demonstration, to return student scores that were better (or equal to) average for each test:
SELECT s.test_id
, s.avg_score
, t.student_id
, t.score
FROM ( -- inline view to get average score for each test_id
SELECT r.test_id AS test_id
, AVG(r.score) AS avg_score
FROM test_score r
GROUP
BY r.test_id
) s
LEFT
JOIN test_score t
ON t.test_id = s.test_id
AND t.score >= s.avg_score
ORDER
BY t.test_id
, s.score DESC
And we'd expect that to return something like:
test_id avg_score student_id score
------- --------- ---------- -----
101 83 6 90
101 83 8 88
222 84 6 93
The first two columns, returned from the inline view, are the result of the aggregate (AVG). The last two columns are detail rows, matched to the rows from the aggregate result.
To summarize the main point here:
To return aggregates along with details, we typically need two SELECT.
One SELECT to get the aggregates (with a GROUP BY if the aggregates are "per" each something or other)
Another SELECT to get the details and a match to the aggregate.
If the average score being computed in your query is already correct, you are just having trouble filtering by it, just wrap it in parens and select from it
select * from (
SELECT Count(entry_id) AS Filled,
q.question AS Questions,
AVG(ag.score) AS TOTAL
FROM entry e
LEFT JOIN entry_answer ea
ON ea.entry_id= e.entry
LEFT JOIN question q
ON q.question_id = ea.question_id
LEFT JOIN question_group qg
ON ea.question_parent_id = qg.question_parent_id
LEFT JOIN answer_group ag
ON ag.question_id = qg.question_parent_id
JOIN sent_list using (sent_list_id)
WHERE
entry_group_id = 2427
AND ag.score >= 0
AND ea.rated_answer_id = ag.rated_answer_id
AND sent_id = 6156
AND e.entry_date BETWEEN '2018-01-01' AND '2019-12-31'
group by ea.question_id
) results where total >= 81
I am new with mysql and working to change a store application to make it have two stock. I created a table to store stock quantity:
Then I plan to create a view with stock quantity, per store, per SKU. I using the following query:
SELECT
`stockList`.`sku`,
SUM(A.`stockQty`) AS 'store1',
SUM(B.`stockQty`) AS 'store2',
SUM(`stockList`.`stockQty`) AS 'total'
FROM `stockList`
LEFT JOIN (
SELECT * FROM `stockList` WHERE `idStock`=1
) AS A
ON `stockList`.`sku`=A.`sku`
LEFT JOIN (
SELECT * FROM `stockList` WHERE `idStock`=2
) AS B
ON `stockList`.`sku`=B.`sku`
GROUP BY `stockList`.`sku`
Per resulting table, calculation is not proper and I could not identify the logic:
SKU 43 should show for store1 = 9 and for store2 = 10, total = 19. This is what they show if I execute the select queries alone. Please, let me know if I misunderstood how this sum logic works.
You might to use SUM on subquery to calculate Totle price by sku
LEFT JOIN may make some fields not match causing NULL so use IFNULL to preset value 0
You can try this.
SELECT
T.sku,
SUM(T.stockQty) as totle,
IFNULL(A.`store1`,0) AS `store1`,
IFNULL(B.`store2`,0) AS `store2`
FROM `stockList` AS T
LEFT JOIN
(
SELECT sku,SUM(`stockQty`) as `store1`
FROM `stockList`
WHERE `idStock`=1
GROUP BY sku
) as A ON A.sku = T.sku
LEFT JOIN
(
SELECT sku,SUM(`stockQty`) as `store2`
FROM `stockList`
WHERE `idStock`=2
GROUP BY sku
) AS B ON T.sku =B.sku
GROUP BY T.sku
sqlfiddle
Your query is much more complicated than it needs to be. You can just do this:
SELECT
sku,
SUM(stockQty) as total,
SUM(IF(idStock=1,stockQty,0)) AS `store1`,
SUM(IF(idStock=2,stockQty,0)) AS `store2`
FROM `stockList`
GROUP BY sku
Output:
sku total store1 store2
36 10 10 0
37 3 3 0
38 4 4 0
39 3 3 0
40 10 10 0
41 12 12 0
42 12 12 0
43 19 9 10
I have tables as below -
Employee -
Employee_Id Name Limit_Amt
1 Sachin 3000
2 Mahi 2500
Employee_Wage -
Employee_Id Amount Pay_Date
1 200 2017-01-01
1 250 2017-02-01
1 300 2017-03-01
2 350 2017-01-01
2 400 2017-02-01
2 300 2017-03-01
Now to find out Remaining limit for individual employee below query works fine -
SELECT e.Limit_Amt - SUM(Amount) AS 'Remaining Limit'
FROM Employee e, Employee_Wage ew
WHERE e.Employee_Id = ew.Employee_Id
GROUP BY e.Employee_Id, e.Limit_Amt
It gives output as -
Remaining Limit
2250
1450
But, further I wish to calculate Total of remaining limit (i.e. deriving 3700), then if I apply SUM(e.Limit_Amt - SUM(Amount)) ... it's not working.
Conceptually I am blocked. Could someone please guide me here? Thanks in advance.
You could use a subquery:
SELECT SUM(remaining)
FROM (
SELECT e.Limit_Amt - SUM(Amount) AS remaining
FROM Employee e
JOIN Employee_Wage ew
ON e.Employee_Id = ew.Employee_Id
GROUP BY
e.Employee_Id
, e.Limit_Amt
) sub
The from a join b on a.id = b.id syntax is clearer than SQL92's from a, b where a.id = b.id.
select e.Name,e.Limit_Amt,sum(cast(w.Amount as int)) 'sum',
e.Limit_Amt-sum(cast(w.Amount as int)) 'Remaining'
from Employee e join Employee_Wage w
on e.Employee_Id=w.Employee_Id
group by e.Name,e.Limit_Amt