Issue while Combining multiple rows in MySQL - mysql

I want to build the query according to the following conditions,
I just want to combine the sum the Total price of both type 1 and type 2.
Combine 2 rows into 1 and avoid null values in that rows.
Query,
select B.ID as BillId,
I.Id as ItemID,
t.Type,
SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2
from Bill B
inner join ItemDetails I
on I.BillNoID = B.ID
inner join TaxDetails T
on T.ItemDetailId = I.Id
group by
B.ID,
I.Id,
I.TotalPrice,
t.Type;
Please refer below image,
Expected Output:
'1', '1', NULL, '40.00', '3.00', '5.00'
Note:
1. I dont want to use sub-query.
2. Expected output "NULL" refers i don't want to show that column seperately.

Sounds like this would solve your problem. If not please give more informations.
SELECT B.ID as BillId, I.Id as ItemId,
t.type, SUM(TotalPrice), SUM(TaxAmountType1),
SUM(TaxAmountType2)
FROM Bill B
GROUP BY BillId, ItemId, t.type

Don't group by the column that you're trying to aggregate. Remove the I.TotalPrice from the GROUP BY:
select B.ID as BillId, I.Id as ItemID, t.Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2 from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, t.Type;`

Try
select B.ID as BillId, I.Id as ItemID, null as Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2
from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, I.TotalPrice
You don't want to group by type, that's the issue (you also can remove the ", null as Type" from the select)

If you group by t.type, you wont be able to have those instances in the same line.
Try:
select B.ID as BillId, I.Id as ItemID, t.Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2 from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, I.TotalPrice;

Related

Rewriting a query that has two sub queries using no sub queries

Given the database schema:
Part( PID, PName, Producer, Year, Price)
Customer( CID, CName, Province)
Supply(SID, PID, CID, Quantity, Amount, Date)
And the query:
Select cname, Province
From Customer c
Where exists (
Select *
from Supply s
join Part p on p.pId = s.pId
Where CId = c.CId
and p.Producer = 'Apple'
)
and Not exists (
Select *
from Supply n
join Part nap on nap.pId = n.pId
Where CId = c.CId
and nap.Producer != 'Apple'
)
How would I go about rewriting this query without the two sub queries?
You can use the LEFT JOIN/NULL pattern to find customers who haven't bought any non-Apple products. Then you can do this all with just joins. You'll have to join with Supply and Parts twice, once for finding Apple products, then again for excluding non-Apple products.
SELECT distinct c.name, c.province
FROM Customer AS c
JOIN Supply AS s1 ON s1.cid = c.cid
JOIN Parts AS p1 ON p1.pid = s1.pid
LEFT JOIN Supply AS s2 ON s2.cid = c.cid
LEFT JOIN Parts AS p2 ON p2.pid = s2.pid AND p2.producer != 'Apple'
WHERE p1.producer = 'Apple' AND p2.pid IS NULL
Notice that in the LEFT JOIN you put restrictions of the second table in the ON clause, not the WHERE clause. See Return row only if value doesn't exist for more about this part of the query.
You want customer who only bought Apple products?
One possible solution is based on conditional aggregation:
Select c.cname, c.Province
From Customer c
join
( -- this is not a Subquery, it's a Derived Table
Select s.CId -- assuming there's a CId in Supply
from Supply s
join Part p
on p.pId = s.pId
group by s.CId
-- when there's any other supplier this will return 1
having max(case when p.Producer = 'Apple' then 0 else 1 end) = 0
) as p
on p.CId = c.CId

Group and count rows and then use them in condition

I have an query like:
SELECT * FROM account AS a
LEFT JOIN (SELECT SUM(bill.amount) total, bill.accountId FROM bill GROUP BY bill.accountId) b ON a.id = b.accountId
WHERE a.partner_id = 1 OR a.partner_id = 2
How can I check, how many groups in "bill" has the same a.partner_id?
For example: 3 groups has partner_id = 1, 2 groups has partner_id = 2.
And later include to left join only groups, if more than 2 groups have the same partner_id.
If I understand correctly, you just want an aggregation on top of your query:
SELECT a.partner_id, count(*) as cnt, sum(total) as total
FROM account a LEFT JOIN
(SELECT SUM(b.amount) as total, b.accountId
FROM bill b
GROUP BY b.accountId
) b
ON a.id = b.accountId
GROUP BY a.partner_id;
You should be able to use the "HAVING" clause. Below is an example from the following link:
https://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html
SELECT name, COUNT(name) AS c FROM orders
GROUP BY name
HAVING c = 1;

How Do I Count Number of Males and Females

I have the query as follows:
select d.question, b.response, count(b.response)
from sl_flow a
INNER JOIN ul_attempt_responses b on a.question_id = b.question_id and b.type = 1
INNER JOIN us_attempts c on c.id = b.attempt_id
INNER JOIN ss_questions d on d.id = a.question_id
where a.status = 1
and a.ckm_question = 0
and b.response
group by a.question_id, b.response
order by a.question_order asc
The above gives me the questions that I have in the DB which are active and their responses and counts.
However I need a query that will give me number of males and females that answered each of the question. Therefore, I have another query that gives me the number of males and females which is:
SELECT
concat(a.response, 's') as gender,
count(a.response) as count
FROM
ul_attempt_responses a
INNER JOIN us_attempts b ON a.attempt_id = b.id
WHERE
a.question_id = 6 and a.type = 0 AND trim(a.response) != ''
GROUP by a.response;
I am not sure, how to do so. For the gender, the question_id is 6 and type on the a table has to be 0 (the a table is ul_attempt_responses).
This is what I got so far. However, it appears that the results I am getting may not be consistent:
SELECT
gender.question
,coalesce(sum(case final.Response when 'male' then gender.total end),0) as 'Males'
,coalesce(sum(case final.Response when 'female' then gender.total end),0) as 'Females'
FROM
(SELECT
stats . *,
(CASE concat(stats.userid, stats.QuestionID, stats.type)
WHEN #curType THEN #curRow:=coalesce(#curRow, 0) + 1
ELSE #curROw:=1
AND #curType:=concat(stats.userid, stats.QuestionID, stats.type)
END) + 1 AS rank
FROM
(SELECT
d.question as Question,
a.user_id AS UserID,
c.question_id AS QuestionID,
c.type as Type,
c.response AS Response,
a.campaign_id as campaign_id
FROM
us_attempts a
INNER JOIN ul_attempt_responses c ON a.id = c.attempt_id
RIGHT OUTER JOIN ss_profile_questions d ON c.question_id = d.id AND c.type = 0
LEFT OUTER JOIN sl_profile_flow f ON c.question_id = f.profile_question_id
RIGHT OUTER JOIN us_users g ON g.id = a.user_id
WHERE
f.status = 1
ORDER BY a.user_id , c.question_id , c.type , a.id desc) stats) final
INNER JOIN
(select b.user_id, c.question as question, count(1) as total
from ul_attempt_responses a
INNER JOIN us_attempts b on a.attempt_id = b.id
INNER JOIN ss_questions c on a.question_id = c.id and a.type = 1
group by b.user_id, c.id) gender on final.UserID = gender.user_id
where
final.rank = 2 and final.QuestionID = 6 and final.campaign_id = 3
group by gender.question;
Is there a way I can reduce the above query, or is there a better optimized way?
You could use a combination of sum and case/if to get the counts. Given your full table structures are not clear, I am assuming you have a table (or an SQL that can produce a set of rows) with the following fields:
response_id
question_id
response
Then an SQL such as
select question_id
, response
, sum(if(gender='M',1,0)) as males
, sum(if(gender='F',1,0)) as females
from (select q.question_id
, q.response
, g.response as gender from answers as q
left join answers as g on q.response_id=g.response_id and g.question_id=6
where q.question_id!=6) as t
group by question_id, response
would give you a result of the form
question_id,response,males,females
1,A,1,2
1,B,1,0
2,A,0,1
2,B,1,1
2,C,1,0
To explain the code, the sub query produces a set of rows for each response with the question mapped with the gender question's response. In the main select statement the if statement produces a 1 for the specific gender in the proper column and summing them up gives you how many of that specific gender responded to that question.
EDIT
As suggested by #Strawberry, the shorter version would be
select q.question_id
, q.response_id
, sum(g.response='M') as males
, sum(g.response='F') as females
from answers as q
left
join test as g
on q.response_id = g.response_id
and g.question_id = 6
where q.question_id != 6
group
by q.question_id
, q.response

Issue to get total amount while using inner join in MYSQL

I get an wrong TotalPrice from the ItemDetails table while join the taxdetails table.
Code 1:
select Distinct B.ID as BillId,
I.ID as ItemDetailId,
I.TotalPrice as ItemPrice,
T.Amount as TaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id;
Refer below image,
While sum the TotalPrice and TotalTaxAmount on the same query i got an wrong TotalPrice result,
Code 2:
select Distinct B.ID as BillId,
SUM(I.TotalPrice) as TotalPrice,
SUM(T.Amount) as TotalTaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID;
Please refer below image,
Actual issue is as per taxdetails per itemdetail each row the rows become multiple so the totalprice get differs.
Expected Output for code 2 (i have listed the first row expected result) is,
Billid TotalPrice TotalTaxAmount
1 70 30
Try this,you have multiple items/bill, that is why you can't make inner join directly.Remove group by also.
select B.ID as BillId,
I.TotalPrice as TotalPrice,
T.Amount as TotalTaxAmount from Bill B
inner join
(
select BillNoID,SUM(TotalPrice) as TotalPrice from ItemDetails
group by BillNoID
)as I on I.BillNoID = B.ID
inner join
(
Select ItemDetailId,SUM(Amount) as Amount from TaxDetails
group by ItemDetailId
)as T on T.ItemDetailId = I.Id

MySQL how do I not include duplicate rows when I use SUM and COUNT with multiple INNER JOINS?

SELECT SUM(case when p.status = 2 then p.value end) as 'val_accepted'
FROM
props AS p
INNER JOIN (p_contents AS pc
INNER JOIN contents AS c ON c.id = pc.library_id)
ON p.id = pc.prop_id
WHERE p.account_id = 3
GROUP BY (pc.library_id)
so, what's happening:
there are two p_contents that are associated with a prop. those two p_contents have the same library_id which points to a corresponding content.
So, the SUM of p.value is double what it should be because there are two p_contents that point to the same content
How do I not double SUM the p.value?
EDIT:
I figured out how to use DISTINCT, but I still need access to the inner columns...
SELECT c.name as 'library_name',
SUM(case when p.status = 2 then p.value end) as 'val_accepted',
FROM
props AS p
INNER JOIN
(
SELECT DISTINCT(pc.library_id), prop_id
FROM prop_contents AS pc
INNER JOIN
(
SELECT name, visibility, id, updated_at
FROM contents AS c
) as c
ON c.id = pc.library_id
)as pc
ON p.id = pc.prop_id
WHERE p.account_id = 3
GROUP BY (pc.library_id)
and now I get the error:
Unknown column 'c.name' in 'field list')
Here's one solution. First reduce the set to distinct rows in an derived table, then apply the GROUP BY to that result:
SELECT SUM(case when d.status = 2 then d.value end) as 'val_accepted'
FROM (
SELECT DISTINCT p.id, p.status, p.value, pc.library_id
FROM props p
INNER JOIN p_contents AS pc ON p.id = pc.prop_id
INNER JOIN contents AS c ON c.id = pc.library_id
WHERE p.account_id = 3) AS d
GROUP BY d.library_id
You use DISTINCT(pc.library_id) in your example, as if DISTINCT applies only to the column inside the parentheses. This is a common misconception. DISTINCT applies to all columns of the select-list. DISTINCT is not a function; it's a query modifier.