order, group and search query. too many selects - mysql

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"
)

Related

Most efficient way to Select all, and to include a distinct column value - while ordering by date added

I have rows that get updated automatically. Sometimes rows are updated (via a new insert - an almost duplicate row) where some columns remain the same - and other columns have new values. I want to pull the most recent up to date row; all the values. Here's what I've got
SELECT * FROM
(SELECT * FROM
(SELECT * FROM entries
WHERE dataset_id = xxx
ORDER BY time_added DESC
) alias1 GROUP BY title
) alias2 ORDER BY timestamp
Work backwards on this list:
SELECT #1 > Reorders these to be displayed based on the timestamp initially created (not added)
SELECT #2 > Filters Select #3 to select distinct title values (most recent title)
SELECT #3 > First query actually executed. Gets the dataset orderd by timestamp added
Is there a more efficient way to do this? I get serious code bad smell from it.
Use a group by and join:
select e.*
from entries e join
(select title, max(time_added) as maxta
from entries e
where dataset_id = xxx
group by title
) emax
on emax.title = e.title and e.time_added = emax.maxta
where dataset_id = xxx
order by e.timestamp;
Your method uses a MySQL extension to group by, where you have columns in the select list that are not in the group by. This is explicitly documented to return indeterminate results. Don't use features that are documented not to work, even if they seem to under some circumstances.

SubQuery Join Failed

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

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 If Exists Set Value?

I have a query that returns a bunch of information and using a join to join two tables and it works perfectly fine.
But I have a field called tickets which I need to see if there is a time available and if there is even one set it to 1 otherwise set it to 0. So like this.
SELECT
name,poster,sid,tickets = (IF SELECT id FROM times WHERE shows.tid=times.tid LIMIT 1,
if value returned set to 1, otherwise set to 0)
FROM shows JOIN show_info ON (id) WHERE sid=54 order by name ASC
Obviously that is not a correct MySQL statement, but it would give an example of what I am looking for.
Is this possible? Or do I need to do the first select then for a loop through results and do the second select and set value that way? Or is one better performance wise?
I would look at EXISTS it is in most of the cases much faster then to COUNT all the items that matches your where statement. With that said. You query should look something like this:
SELECT
name,
poster,
sid,
(
CASE WHEN EXISTS(SELECT NULL FROM times WHERE shows.tid=times.tid)
THEN 1
ELSE 0
END
)AS tickets
FROM
shows
JOIN show_info ON (id) WHERE sid=54 order by name ASC
Look at CASE statement
SELECT name,poster,sid,
Case WHEN (SELECT count(id) FROM times WHERE shows.tid=times.tid) > 0 THEN 1 else 0 END as Tickets
FROM shows
JOIN show_info ON (id)
WHERE sid=54 order by name ASC
try
SELECT
name,
poster,
sid,
CASE WHEN (SELECT COUNT(*) FROM times WHERE shows.tid=times.tid ) > 0 THEN 1 ELSE 0 END CASE tickets
FROM shows
JOIN show_info ON (id)
WHERE sid=54
order by name ASC
For reference on CASE see MySQL Docs.
This is the simplest way to do this I can think of:
SELECT name, poster, sid,EXISTS(SELECT * times WHERE shows.tid=times.tid) tickets
FROM shows
JOIN show_info USING (id)
WHERE sid = 54
ORDER BY name

MySQL Query needs to bring back rows, not empty results

OK, I've voted to delete my earlier question due to stupidity on my part...
I have the following code:
SELECT qnum, id, name, total_staff AS StaffCount, COUNT( q61g ) AS TotalResp,
(COUNT( q61g ) / total_staff * 100) AS Perc
FROM tdemog_pfp
LEFT JOIN tresults_pfp ON tdemog_pfp.id = tresults_pfp.q61g
WHERE qnum = 'q61g' AND q60p = '1'
GROUP BY name
ORDER BY name
Now, the first part of this query brings back rows from the tdemog table, for example it will bring back 5 rows of data each row has an id from 1 to 5. What I need the query to do is then bring back data from the tresults table WHERE q60p = 1 for each of the 5 rows brought back in the first part - like a normal `LEFT JOIN'.
Make sense?
H.
Try moving part of your WHERE clause into your JOIN condition:
SELECT ...
FROM tdemog_pfp
LEFT JOIN tresults_pfp ON tdemog_pfp.id = tresults_pfp.q61g AND q60p = '1'
WHERE qnum = 'q61g'
GROUP BY name
ORDER BY name
If you have a field from your second table in your WHERE clause, it will restrict the entire record... but if you put it into your JOIN condition, the record from the first table should still be returned even when the record in the second table doesn't meet the additional criteria...
I'm not sure which column belongs to which table... but move whatever columns are in your second table into your JOIN.