refrence parent field from sub inner join select - mysql

I have this query that select records from a table and LEFT JOINS other two tables.
Here's the query
SELECT mainTest.lab_number_auto, mainTest.lab_number,
SUM(CASE WHEN test.lab_number = mainTest.lab_number
THEN test.test_unit_cost ELSE 0 END) cost,
payment.totalPaid
FROM patient_main_test mainTest
LEFT JOIN patient_test test
ON test.lab_number = mainTest.lab_number
LEFT JOIN (
SELECT SUM(CASE WHEN testpayment.lab_number = mainTest.lab_number THEN testpayment.amount_paid ELSE 0 END) totalPaid
FROM patient_test_payment testpayment
GROUP BY testpayment.lab_number
) AS payment
ON payment.lab_number = mainTest.lab_number
WHERE mainTest.lab_number != ''
GROUP BY mainTest.lab_number
On running this query i get this error
MySQL said:
#1054 - Unknown column 'mainTest.lab_number' in 'field list'
Thanks.
Here's a fiddle i created.
http://sqlfiddle.com/#!2/291c4/8

Try this, if im right the issue is that you were trying to treat your derived table in the left join like a co-related sub-query. & thx for the sql fiddle... makes it so much easier to help you.
SELECT mainTest.lab_number_auto, mainTest.lab_number,
SUM(CASE WHEN test.lab_number = mainTest.lab_number
THEN test.test_unit_cost ELSE 0 END) cost,
(
SELECT SUM(CASE WHEN testpayment.lab_number = mainTest.lab_number THEN testpayment.amount_paid ELSE 0 END) totalPaid
FROM patient_test_payment testpayment
Where lab_number = mainTest.lab_number
GROUP BY testpayment.lab_number
) AS totalPaid
FROM patient_main_test mainTest
LEFT JOIN patient_test test
ON test.lab_number = mainTest.lab_number
WHERE mainTest.lab_number != ''
GROUP BY mainTest.lab_number

Related

Update a column in mysql based on where statement with subselects

I have this pseudo SQL code for what I want to achieve:
UPDATE orders o
SET o.datePaid = null
WHERE
(
SELECT SUM(amount)
FROM transactions t
WHERE t.orderId = o.id
AND t.status = 'success'
AND t.type = 'refund'
)
>=
(
SELECT SUM(amount)
FROM transactions t
WHERE t.orderId = o.id
AND t.status = 'success'
AND t.type IN ('purchase', 'capture')
)
How would I do this in SQL?
I think your approach is interesting. Here is a more concise method:
UPDATE orders o
SET o.datePaid = null
WHERE (SELECT SUM(CASE WHEN t.type = 'refund' THEN amount
WHEN t.type IN ('purchase', 'capture') THEN -amount
END)
FROM transactions t
WHERE t.orderId = o.id AND
t.status = 'success'
) > 0;
Your query works fine as is. However it can be more optimally written using MySQL multi-table UPDATE syntax:
UPDATE orders o
LEFT JOIN (SELECT orderId,
COALESCE(SUM(CASE WHEN type = 'refund' THEN amount END), 0) AS refunds,
COALESCE(SUM(CASE WHEN type IN ('purchase', 'capture') THEN amount END), 0) AS pc
FROM transactions
WHERE status = 'success'
GROUP BY orderId) t ON t.orderId = o.id
SET o.datePaid = NULL
WHERE t.refunds > t.pc
Demo on dbfiddle (includes your query working as well)
Your code would probably work just as it is. Give it a try.
You could also optimize the query to avoid the need for two subqueries by using a JOIN and conditional aggregation in a single subquery:
UPDATE orders o
INNER JOIN (
SELECT orderId
FROM transactions
WHERE
status = 'success'
AND type IN ('success', 'purchase', 'capture') -- this condition might be superfuous
GROUP BY o.id
HAVING
SUM(CASE WHEN type = 'success' THEN amount ELSE 0 END)
>= SUM(CASE WHEN type IN ('purchase', 'capture') THEN amount ELSE 0 END)
) t ON t.orderId = o.id
SET o.datePaid = null
Note: WHERE condition AND type IN ('success', 'purchase', 'capture') is superfluous if that list of 3 values represents all the possible values.

MySQL select query, adding max value from another table

Trying to add another column with a new table, would appreciate any help/suggestions!
Current query:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
And that works fine, gives 1 row of results. I'd now like to add another column to the results, I believe a left outer join from the prices table of the record that is the closest date before 2017-12-31. My attempt:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25',
MAX(case when date_format(p.date, '%Y-%m-%d') <= '2017-12-31' then (p.value_num/p.value_denom) else '0' end) AS 'price2017-12-31'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
LEFT OUTER JOIN prices as p ON p.commodity_guid = a.commodity_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
It's obviously incorrect as it's now changing the values of value2017-12-31 and value2018-01-25. I get the price correctly using a separate query:
SELECT p.value_num/p.value_denom as calcprice
FROM `prices` as p
WHERE commodity_guid = '77be249d12d9889e90f08dde7c671eb0'
AND date_format(p.date, '%Y-%m-%d') <= '2017-12-31'
order
by date DESC
limit 1
Is there any way to combine them rather than using temp tables?

Can I break an SQL statement with JOINs into smaller queries or optimize query?

I have query that's breaking an area of my website. The site spins forever when attempting to load the following SQL statement! I'm fairly new to sql statements and this particular statement was created by another developer. Is there a way to optimize the following statement? Or break it up into smaller statements so that it will run more quickly? I'm at a loss! I appreciate any help.
SELECT
`wp_quiz_users`.`Id`,
`wp_quiz_users`.`SessionId`,
`wp_quiz_users`.`Score`,
`wp_quiz_users`.`Date`,
`wp_quiz_users`.`Referrer`,
`wp_quiz_users`.`ContactData`,
(SELECT
SUM(`wp_quiz_users_answers`.`AnswerValue`)
FROM
`wp_quiz_users_answers`
JOIN
`wp_quiz_questions`
ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id`
WHERE
`wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id`
AND `wp_quiz_questions`.`Category` = 1) AS `SectionOne`,
(SELECT
SUM(`wp_quiz_users_answers`.`AnswerValue`)
FROM
`wp_quiz_users_answers`
JOIN
`wp_quiz_questions`
ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id`
WHERE
`wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id`
AND `wp_quiz_questions`.`Category` = 2) AS `SectionTwo`,
(SELECT
SUM(`wp_quiz_users_answers`.`AnswerValue`)
FROM
`wp_quiz_users_answers`
JOIN
`wp_quiz_questions`
ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id`
WHERE
`wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id`
AND `wp_quiz_questions`.`Category` = 3) AS `SectionThree`,
(SELECT
SUM(`wp_quiz_users_answers`.`AnswerValue`)
FROM
`wp_quiz_users_answers`
JOIN
`wp_quiz_questions`
ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id`
WHERE
`wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id`
AND `wp_quiz_questions`.`Category` = 4) AS `SectionFour`,
(SELECT
SUM(`wp_quiz_users_answers`.`AnswerValue`)
FROM
`wp_quiz_users_answers`
JOIN
`wp_quiz_questions`
ON `wp_quiz_users_answers`.`QuestionId` = `wp_quiz_questions`.`id`
WHERE
`wp_quiz_users_answers`.`UserId` = `wp_quiz_users`.`Id`
AND `wp_quiz_questions`.`Category` = 5) AS `SectionFive`
FROM
`wp_quiz_users`
This answer is similar to Gordon's except that it performs the aggregation for the sums inside a separate subquery. This frees the outer query from needing to aggregate, and hence there should be no problem at all selecting any columns we want from the wp_quiz_users table.
SELECT
t1.Id,
t1.SessionId,
t1.Score,
t1.Date,
t1.Referrer,
t1.ContactData,
COALESCE(t2.SectionOne, 0) AS SectionOne,
COALESCE(t2.SectionTwo, 0) AS SectionTwo,
COALESCE(t2.SectionThree, 0) AS SectionThree,
COALESCE(t2.SectionFour, 0) AS SectionFour,
COALESCE(t2.SectionFive 0) AS SectionFive
FROM wp_quiz_users t1
LEFT JOIN
(
SELECT
t1.UserId,
SUM(CASE WHEN t2.Category = 1 THEN t1.AnswerValue ELSE 0 END) AS SectionOne,
SUM(CASE WHEN t2.Category = 2 THEN t1.AnswerValue ELSE 0 END) AS SectionTwo,
SUM(CASE WHEN t2.Category = 3 THEN t1.AnswerValue ELSE 0 END) AS SectionThree,
SUM(CASE WHEN t2.Category = 4 THEN t1.AnswerValue ELSE 0 END) AS SectionFour,
SUM(CASE WHEN t2.Category = 5 THEN t1.AnswerValue ELSE 0 END) AS SectionFive
FROM wp_quiz_users_answers t1
INNER JOIN wp_quiz_questions t2
ON t1.QuestionId = t2.id
GROUP BY t1.UserId
) t2
ON t1.Id = t2.UserId;
I think you just want conditional aggregation:
SELECT qu.*,
SUM(CASE WHEN qq.Category = 1 THEN qa.AnswerValue END) as SectionOne,
SUM(CASE WHEN qq.Category = 2 THEN qa.AnswerValue END) as SectionTwo,
SUM(CASE WHEN qq.Category = 3 THEN qa.AnswerValue END) as SectionThree,
SUM(CASE WHEN qq.Category = 4 THEN qa.AnswerValue END) as SectionFour,
SUM(CASE WHEN qq.Category = 5 THEN qa.AnswerValue END) as SectionFive
FROM wp_quiz_users qu LEFT JOIN
wp_quiz_users_answers qa
ON qa.UserId = q.id LEFT JOIN
wp_quiz_questions qq
ON qa.QuestionId = qq.id
GROUP BY qu.UserId;
This is similar to that by Gordon Linoff but I wanted to add a note on syntax you may need at some point. Standard behaviour for SQL is that all columns that do not involve an aggregation function [e.g. sum()] should be listed in the group by clause.
SELECT
wp_quiz_users.Id
, wp_quiz_users.SessionId
, wp_quiz_users.Score
, wp_quiz_users.Date
, wp_quiz_users.Referrer
, wp_quiz_users.ContactData
, SUM(CASE WHEN qq.Category = 1 THEN qa.AnswerValue END) AS sectionone
, SUM(CASE WHEN qq.Category = 2 THEN qa.AnswerValue END) AS sectiontwo
, SUM(CASE WHEN qq.Category = 3 THEN qa.AnswerValue END) AS sectionthree
, SUM(CASE WHEN qq.Category = 4 THEN qa.AnswerValue END) AS sectionfour
, SUM(CASE WHEN qq.Category = 5 THEN qa.AnswerValue END) AS sectionfive
FROM wp_quiz_users qu
LEFT JOIN wp_quiz_users_answers qa ON qa.UserId = q.id
LEFT JOIN wp_quiz_questions qq ON qa.QuestionId = qq.id
GROUP BY
wp_quiz_users.Id
, wp_quiz_users.SessionId
, wp_quiz_users.Score
, wp_quiz_users.Date
, wp_quiz_users.Referrer
, wp_quiz_users.ContactData
;
i.e. It is good practice to list out all the columns you need in the select clause, and also all the "non-aggregating" columns also listed in the group by clause.
IF you see a query using like this:
select * from sometable group by name
Then that query relies an a non-standard MySQL extension that can be turned on or off. If that extension is turned off queries reliant on the extension will begin to fail. So, a prudent coder can avoid that potential problem by simply listing all the non-aggregating columns in the group by clause. see: https://dev.mysql.com/doc/refman/5.7/en/group-by-modifiers.html
Regarding the original query it contains many "correlated subqueries" inside the select clause, and as you have discovered that are awful for performance. Be on the lookout for these
select name
, (select sum(value) from tablex
where tablex.id = table1.id -- the "correlation" of tablex to table1 is here
)
from table1
Occasionally however they can be a decent option, so while thay are to be avoided most of the time we cannot just say never use them at all.
I would start with
FROM (
SELECT ua.`UserId`,
q.Category,
SUM(ua.`AnswerValue`)
FROM `wp_quiz_users_answers` AS ua
JOIN `wp_quiz_questions` AS q
ON ua.`QuestionId` = q.`id`
GROUP BY ua.`UserId`, q.Category
) AS x
JOIN wp_quiz_users AS u
ON u.Id = x.UserId
and build up around it.
(But since I see other answers, I'll be lazy and not finish this thought.)
Hmmm... I wonder if my approach -- or the other approaches -- will inflate the SUMs due to waiting too late to do GROUP BY??

MS SQL case inside count

I have zero experience in MS SQL and I'm tearing my hair out trying to convert my MySQL query:
select
m.Customer,
count(if(c.AtFault="Me",1,null)) 'MeLate',
count(if(c.AtFault="You",1,null)) 'YouLate',
count(*) 'Total'
from m
left join r on m.OrderNumber = r.OrderNumber
left join c on r.ReasonCodeID = c.ID
group by m.Customer
This is what I'm trying to run on MS SQL:
select
m.Customer
count(CASE WHEN c.AtFault="Me" THEN 1 ELSE null) 'MeLate',
count(CASE WHEN c.AtFault="You" THEN 1 ELSE null) 'YouLate',
count(*) 'Total'
from m
left join r on m.OrderNumber = r.OrderNumber
left join c on r.ReasonCodeID = c.ID
group by m.Customer
but this throws the uninformative error:
SQL Error (102): Incorrect syntax near ')'.
Three errors:
You are missing the END at the end of CASE WHEN.
You must use single quote instead double.
Forgot the comma after m.Customer
Try this:
select
m.Customer,
count(CASE WHEN c.AtFault='Me' THEN 1 ELSE null END) MeLate,
count(CASE WHEN c.AtFault='You' THEN 1 ELSE null END) YouLate,
count(*) Total
from m
left join r on m.OrderNumber = r.OrderNumber
left join c on r.ReasonCodeID = c.ID
group by m.Customer
end is missing there and you can try sum instead of count
select
m.Customer,
sum(CASE WHEN c.AtFault='Me' THEN 1 ELSE 0 end) MeLate,
sum(CASE WHEN c.AtFault='You' THEN 1 ELSE 0 end) YouLate,
count(*) Total
from m
left join r on m.OrderNumber = r.OrderNumber
left join c on r.ReasonCodeID = c.ID
group by m.Customer

Translate MYSQL query to HQL using multiple JOINS

everyone.
I am using grails 3.3.0.M2 framework with mysql as data-source the following sql query is working as expected
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) 'open',
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) 'in progress',
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) 'closed'
FROM
tickets t
INNER JOIN
users u ON t.user_id = u.id
INNER JOIN
user_coordinations uc ON uc.user_id = u.id
INNER JOIN
coordinations c ON c.id = uc.coordination_id
GROUP BY 1
I translated to HQL using implicit JOIN but I am getting the wrong results, here is the hql query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t, User u, UserCoordination uc, Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
In order to get the right results stack overflow users help me to understand that the query needs to use explicit JOINS, here the question: Group by a field that does not belongs to the consulted table
Right now I am trying with the following query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t
INNER JOIN
User u
INNER JOIN
UserCoordination uc
INNER JOIN
Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
But i am getting a com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException with the caused message You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'inner join user_coordinations usercoordi2_ on inner join coordinations coordinat' at line 1
Thanks for your help and time
SELECT new map(
c.name as name,
(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) as open,
(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) as pending,
(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) as closed,
SUM(open) as openSum,
SUM(pending) as pendingSum,
SUM(closed) as closedSum
)
FROM
Ticket t
left join t.user u left join u.userCoordination uc left join uc.coordination c
WHERE
MONTH(t.dateCreated) = :month
//GROUP BY 1
What you had had lots missing above is more like what you need, you need
select new map(i.item as item... if you compare the basics of this with what you had and what i tried to do you can see why you had errors.
unsure about your group by it should be group by something. Wasn't sure by inner join if you just meant a join if that was the case leave out all the left join since left join attempts to connect and get any null hasMany relations etc.