SubQuery Join Failed - mysql

I am trying to find out the missing record in the target. I need the employee whose record are missing.
Suppose I have input source as
1,Jack,type1,add1,reg3,..,..,..,
2,Jack,type2,add1,reg3,..,,.,..,
3,Jack,type3,add2,reg4,..,.,..,.,
4,Rock,,,,,,,,
and I have output as
1,Jack,type1,add1,reg3,..,..,..,
4,Rock,,,,,,,,
I have 1000 numbers of rows for other employees and in target i don't have any duplicate records.
I need the employee who are present in source and target having different occurance
means for e.g in above sample data I have 3 entries of jack and 1 entry of Rock in source
and in target I have only on entry of Jack and one for Rock
I am running below query and required output is Jack,3
How can I get it. I am getting error in below query
select A.EMP_NUMBER,A.CNT1
from
(select EMP_NUMBER,count(EMP_NUMBER) as CNT1
from EMPLOYEE_SOURCE
group by EMP_NUMBER ) as A
INNER JOIN
(select B.EMP_NUMBER,B.CNT2
from (select EMP_NUMBER,count(EMP_NUMBER) as CNT2
from EMPLOYEE_TARGET
group by EMP_NUMBER )as B )
ON (A.EMP_NUMBER = B.EMP_NUMBER)
where A.CNT1 != B.CNT2
Please help.

Why don't get the employee that have different number of rows in the two table when grouped by their name (I suppose Emp_Number is the field that contain the name if that what the query in the question return)
SELECT s.Emp_Number, Count(s.Emp_Number)
FROM EMPLOYEE_SOURCE s
LEFT JOIN EMPLOYEE_TARGET t ON s.Emp_Number = t.Emp_Number
GROUP BY s.Emp_Number
HAVING Count(s.Emp_Number) != Count(t.Emp_Number)

It would be really helpful if you specified the exact error you get.
If this is you actual query there are two things: There's no alias name for the 2nd Derived Table (btw, you don't need it at all) and at least in Teradata !=is not valid, this is SQL and not C.
select A.EMP_NUMBER,A.CNT1
from
(
select EMP_NUMBER,count(EMP_NUMBER) as CNT1
from EMPLOYEE_SOURCE
group by EMP_NUMBER
) as A
INNER JOIN
(
select EMP_NUMBER,count(EMP_NUMBER) as CNT2
from EMPLOYEE_TARGET
group by EMP_NUMBER
) as B
ON (A.EMP_NUMBER = B.EMP_NUMBER)
where A.CNT1 <> B.CNT2
If an employee is missing in the 2nd table you might have to use an Outer Join as Serpiton suggested and add an additional WHERE-condition:
where A.CNT1 <> B.CNT2
or b.CNT2 IS NULL

Related

MySQL Inner join naming error?

http://sqlfiddle.com/#!9/e6effb/1
I'm trying to get a top 10 by revenue per brand for France on december.
There are 2 tables (first table has date, second table has brand and I'm trying to join them)
I get this error "FUNCTION db_9_d870e5.SUM does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
Is my use of Inner join there correct?
It's because you had an extra space after SUM. Please change it from
SUM (o1.total_net_revenue)to SUM(o1.total_net_revenue).
See more about it here.
Also after correcting it, your query still had more error as you were not selecting order_id on your intermediate table i2 so edited here as :
SELECT o1.order_id, o1.country, i2.brand,
SUM(o1.total_net_revenue)
FROM orders o1
INNER JOIN (
SELECT i1.brand, SUM(i1.net_revenue) AS total_net_revenue,order_id
FROM ordered_items i1
WHERE i1.country = 'France'
GROUP BY i1.brand
) i2
ON o1.order_id = i2.order_id AND o1.total_net_revenue = i2.total_net_revenue
AND o1.total_net_revenue = i2.total_net_revenue
WHERE o1.country = 'France' AND o1.created_at BETWEEN '2016-12-01' AND '2016-12-31'
GROUP BY 1,2,3
ORDER BY 4
LIMIT 10`
--EDIT stack Fan is correct that the o2.total_net_revenue exists. My confusion was because the data structure duplicated three columns between the tables, including one that was being looked for.
There were a couple errors with your SQL statement:
1. You were referencing an invalid column in your outer-select-SUM function. I believe you're actually after i2.total_net_revenue.
The table structure is terrible, the "important" columns (country, revenue, order_id) are duplicated between the two tables. I would also expect the revenue columns to share the same name, if they always have the same values in them. In the example, there's no difference between i1.net_revenue and o1.total_net_revenue.
In your inner join, you didn't reference i1.order_id, which meant that your "on" clause couldn't execute correctly.
PROTIP:
When you run into an issue like this, take all the complicated bits out of your query and get the base query working correctly first. THEN add your functions.
PROTIP:
In your GROUP BY clause, reference the actual columns, NOT the column numbers. It makes your query more robust.
This is the query I ended up with:
SELECT o1.order_id, o1.country, i2.brand,
SUM(i2.total_net_revenue) AS total_rev
FROM orders o1
INNER JOIN (
SELECT i1.order_id, i1.brand, SUM(i1.net_revenue) AS total_net_revenue
FROM ordered_items i1
WHERE i1.country = 'France'
GROUP BY i1.brand
) i2
ON o1.order_id = i2.order_id AND o1.total_net_revenue = i2.total_net_revenue
AND o1.total_net_revenue = i2.total_net_revenue
WHERE o1.country = 'France' AND o1.created_at BETWEEN '2016-12-01' AND '2016-12-31'
GROUP BY o1.order_id, o1.country, i2.brand
ORDER BY total_rev
LIMIT 10

Return 0 if no records found on COUNT(*) query In MYSQL

I want to get '0' when no records found on execution of sql query. I try so many things like ifnull(count(*),0) but not gives me the result which i want.
Query is mention as below :
SELECT chat_room_id,COUNT(*) FROM chat WHERE sender_id=13 GROUP BY chat_room_id
It gives me the result as below:
__________________________
| chat_room_id | Count(*) |
--------------------------
It not return any 'null' or '0' , so i want to get '0' OR 'null' if no records found.
As long as there is a table Chats with field sender_id then the following will return a row even if the sender_Id 13 does not exist in the table.
set #sender = 13;
set #chats = (select count(*) from Chat where sender_id = #sender);
select #sender AS sender_id, IFNULL(#chats,0) AS Count_chats
;
See this working at SQLFiddle
AFTER YOUR EDIT CHANGES
Try this:
SELECT distinct c1.chat_room_id,
(select count(*) from chat c2 c2.chat_room_id = c1.chat_room_id and c2.sender_id = 13)
FROM chat c1
Pay attention:
A table named CHAT I suppose contains all chats in your DB and no the messages and senders.
Instead if you have a table named CHAT_ROOM with the list of all chats so your query becomes:
SELECT chat_room_id,
(SELECT COUNT(*)
FROM chat
WHERE chat.chat_room_id = chat_room.chat_room_id AND chat.sender_id = 13)
FROM chat_room
You can not query data which is not in the source tables or which is not available with calculation.
If you have a table which contains all available chat rooms, you can use that table to get the desired record with a simple query using LEFT OUTER JOIN
SELECT
CR.chat_room_id,
COUNT(C.chat_room_id)
FROM
chat_rooms CR
LEFT JOIN chat C
ON CR.chat_room_id = C.chat_room_id
AND C.sender_id = 13 -- Moved from WHERE to keep all non-matching records from CR
GROUP BY
CR.chat_room_id
If you do not have a specific table, you can use LEFT OUTER JOIN and a subquery to get the result:
SELECT
CR.chat_room_id,
COUNT(C.chat_room_id)
FROM
(SELECT DISTINCT chat_room_id FROM chat) CR
LEFT JOIN chat C
ON CR.chat_room_id = C.chat_room_id
AND C.sender_id = 13 -- Moved from WHERE to keep all non-matching records from CR
GROUP BY
CR.chat_room_id
SQLFiddle demo for the second query
Are you looking to return all the chat_room_ids in case the sender id does not exist?
like, if say sender_id 9 does not exist, what are you looking to return?
In case you wanted something like
chat_room_id count
NO_RECORDS 0
then the below query will work:
declare #Chat_Room_Id varchar(3),
#Count int
select #Chat_Room_Id = cast(chat_room_id as varchar(3)), #Count = count(*) from chat where sender_id=13 group by chat_room_id
select coalesce(#Chat_Room_Id, 'NO RECORDS') chat_room_id, coalesce(#Count, 0) count
In case I did not understand, can you please clarify further?
-hth
Sourav
you can use mysql_affected_rows(); method to get the details of rows affected with your query.
check this
and this
You can put the sql in a sub query this will always return a row
select sub.id,sub.counter from (select sender_id as id,count(*) as counter from chat where sender_id = 13) sub
This will return 0 if there are no records or 1 if there are.

order, group and search query. too many selects

i am running this query, witch consists of 3 recursive selects.
select idigorUserFields
from ( select *
from ( select *
from igorUserFields f
where f.idigorUsers = 1
order by f.idigorUserFields desc) tbl
group by tbl.idigorUserFieldTemplates ) tbl2
where value="qf" and idigorUserFields = 28
what I am trying to do is simple:
get all fields, order by insert date ( i am using primary key for that )
get the last inserted value for a field (idigorFieldTemplates)
compare the last inserted field with the one i am about to insert, to save some space on the database
some relevant info:
idigorUserFieldTemplates is the primary key for a "html user fields table"
the last inserted value is the one displayed on the program
also, I have a sqlfiddle! with some data to test.
my question is: can I make this query better? and what do I need to use to do that.
Alright so it looks like you want to get the last inserted value for a given user and value and then compare that with the data you are about to insert. Here's how I would tackle that
SELECT a.idigorUserFieldTemplates
FROM igorUserFields AS a
INNER JOIN (SELECT MAX(idigorUserFields) as max_id FROM igorUserFields WHERE idigorUsers = 1 AND value="qf") AS b
ON a.idigorUserFields= b.max_id
The subquery is giving me the largest idigorUserFields for which idigorUsers = 1 AND value="qf." For this to work, you have to assume that that the primary key (idigorUserFields) is incrementing with date. You indicated in your post that it does, so hopefully this assumption is okay.
Once we've got that last updated record, we then join back with igorUserFields to get the corresponding value of idigorUserFieldTemplates
edit:
I want to get the last inserted for a given user and field. then compare it with what i am about to insert.
I am sorry if I was not clear enough about what I wanted.
I modified the above sql and i got what i wanted:
SELECT a.* FROM igorUserFields
AS a INNER JOIN
(SELECT MAX(idigorUserFields) as max_id
FROM igorUserFields WHERE idigorUsers = 1 and idigorUserFieldTemplates =6) AS b
ON a.idigorUserFields= b.max_id
AND value="qf"
thanks! now I got a more efficient solution :)
if all you want is the largest id by specific data just specify that order it and limit it like so
SELECT idigorUserFields
FROM igorUserFields
WHERE idigorUsers = 1 AND value="qf"
ORDER BY idigorUserFields DESC
LIMIT 1
DEMO
if you are trying to get the last inserted value then you can get the largest idigorUserFields assuming its auto incremented.
SELECT MAX(idigorUserFields) FROM idigorUserFields
and then if you want a specific column from that field you could use it as a subquery
SELECT f.idigorUserFieldTemplates
FROM idigorUserFields f
WHERE f.idigorUserFields =
( SELECT MAX(idigorUserFields)
FROM idigorUserFields
WHERE idigorUsers = 1 AND value="qf"
)

COUNT evaluate to zero if no matching records

Take the following:
SELECT
Count(a.record_id) AS newrecruits
,a.studyrecord_id
FROM
visits AS a
INNER JOIN
(
SELECT
record_id
, MAX(modtime) AS latest
FROM
visits
GROUP BY
record_id
) AS b
ON (a.record_id = b.record_id) AND (a.modtime = b.latest)
WHERE (((a.visit_type_id)=1))
GROUP BY a.studyrecord_id;
I want to amend the COUNT part to display a zero if there are no records since I assume COUNT will evaluate to Null.
I have tried the following but still get no results:
IIF(ISNULL(COUNT(a.record_id)),0,COUNT(a.record_id)) AS newrecruits
Is this an issue because the join is on record_id? I tried changing the INNER to LEFT but also received no results.
Q
How do I get the above to evaluate to zero if there are no records matching the criteria?
Edit:
To give a little detail to the reasoning.
The studies table contains a field called 'original_recruits' based on activity before use of the database.
The visits tables tracks new_recruits (Count of records for each study).
I combine these in another query (original_recruits + new_recruits)- If there have been no new recruits I still need to display the original_recruits so if there are no records I need it to evalulate to zero instead of null so the final sum still works.
It seems like you want to count records by StudyRecords.
If you need a count of zero when you have no records, you need to join to a table named StudyRecords.
Did you have one? Else this is a nonsense to ask for rows when you don't have rows!
Let's suppose the StudyRecords exists, then the query should look like something like this :
SELECT
Count(a.record_id) AS newrecruits -- a.record_id will be null if there is zero count for a studyrecord, else will contain the id
sr.Id
FROM
visits AS a
INNER JOIN
(
SELECT
record_id
, MAX(modtime) AS latest
FROM
visits
GROUP BY
record_id
) AS b
ON (a.record_id = b.record_id) AND (a.modtime = b.latest)
LEFT OUTER JOIN studyrecord sr
ON sr.Id = a.studyrecord_id
WHERE a.visit_type_id = 1
GROUP BY sr.Id
I solved the problem by amending the final query where I display the result of combining the original and new recruits to include the IIF there.
SELECT
a.*
, IIF(IsNull([totalrecruits]),consents,totalrecruits)/a.target AS prog
, IIf(IsNull([totalrecruits]),consents,totalrecruits) AS trecruits
FROM
q_latest_studies AS a
LEFT JOIN q_totalrecruitment AS b
ON a.studyrecord_id=b.studyrecord_id
;

MySQL update value from the same table with count

What I want to do is to set every patient its unique patient code which starts with 1 and it's not based on row id. Id only specifies order. Something like this:
patient_id patient_code
2 1
3 2
4 3
This is my query:
UPDATE patients p1
SET p1.patient_code = (
SELECT COUNT( * )
FROM patients p2
WHERE p2.patient_id <= p1.patient_id
)
But it is throwing error:
#1093 - You can't specify target table 'p1' for update in FROM clause
I found this thread: Mysql error 1093 - Can't specify target table for update in FROM clause.But I don't know how to apply approved answer this to work with subquery WHERE which is necessary for COUNT.
UPDATE
patients AS p
JOIN
( SELECT
p1.patient_id
, COUNT(*) AS cnt
FROM
patients AS p1
JOIN
patients AS p2
ON p2.patient_id <= p1.patient_id
GROUP BY
p1.patient_id
) AS g
ON g.patient_id = p.patient_id
SET
p.patient_code = g.cnt ;
I found working solution, but this is just workaround:
SET #code=0;
UPDATE patients SET patient_code = (SELECT #code:=#code+1 AS code)
Try this,
UPDATE patients p1 INNER JOIN
(
SELECT COUNT(*) as count,patient_id
FROM patients
group by patient_id
)p2
SET p1.patient_code=p2.count
WHERE p2.patient_id <= p1.patient_id
SQL_LIVE_DEMO
Thanks to Mari's answer I found a solution to my similar problem. But I wanted to add a bit of an explanation which for me at first wasn't too clear from his answer.
What I wanted to do would have been as simple as the following:
UPDATE my_comments AS c
SET c.comment_responses = (
SELECT COUNT(c1.*) FROM my_comments AS c1
WHERE c.uid = c.parent_uid
);
Thanks to Mari I then found the solution on how to achieve this without running into the error You can't specify target table 'p1' for update in FROM clause:
UPDATE my_comments AS c
INNER JOIN (
SELECT c1.parent_uid, COUNT(*) AS cnt
FROM my_comments AS c1
WHERE c1.parent_uid <> 0
GROUP BY c1.parent_uid
) AS c2
SET c.comment_responses = c2.cnt
WHERE c2.parent_uid = c.uid;
My problems before getting to this solution were 2:
the parent_uid field doesn't always contain an id of a parent which is why I added the WHERE statement in the inner join
I didn't quite understand why I would need the GROUP BY until I executed the SELECT statement on it's own and the answer is: because COUNT groups the result and really counts everything. In order to prevent this behavior the GROUP BY is needed. In my case I didn't have to group it by uid though but the parent_uid to get the correct count. If I grouped it by uid the COUNT would always be 1 but the parent_uid existed multiple times in the result. I suggest you check the SELECT statement on it's own to check if it's the result you expect before you execute the full UPDATE statement.