Table structure:
It is not possible to select records with the maximum delete date, which are grouped by one code, with the condition that they are all deleted. If the records have the same code, but have different delete statuses, then you do not need to select these records.
In this example, you select records with id = 3, id = 4.
SELECT * FROM analyzes_test WHERE code IN (SELECT code FROM analyzes_test GROUP BY code HAVING count(code)>1) AND deleted = (max deleted_date)
But I do not know how to substitute the longest possible date for deletion.
Please tell me who has more experience with sql.
Try the following simple query-:
select code,max(deleted_date) MAX_DeletedDate
from analyzes_test
group by code
having count(deleted_date)>1
you could use an inner join on max date group by code
select *
FROM analyzes_test a
inner join (
select code, max(deleted_date) max_date
FROM analyzes_test
group by code
) t on t.max_date = a.deleted_date and t.code = a.code
or if you don't want thw result for code with only a rows a could use
select *
FROM analyzes_test a
inner join (
select code, max(deleted_date) max_date
FROM analyzes_test
group by code
having count(*)>1
) t on t.max_date = a.deleted_date and t.code = a.code
TRY THIS: GROUP BY and HAVING will help to retrieve the max date of each code and use it as a subquery to retrieve all the information for the table as below:
SELECT ant.*
FROM analyzes_test ant
INNER JOIN (SELECT code, MAX(deleted_date) max_date
FROM analyzes_test
WHERE deleted_date IS NOT NULL
GROUP BY code
HAVING COUNT(deleted_date) > 1) t ON t.code = ant.code
AND t.max_date = ant.deleted_date
Related
I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID
A client can have more than one equipment (SerialNo). Each equipment has a cost and every month there is data recorded for each equipment. I'm trying to select only the first and last result for each equipment based on the queried period.
"
SELECT i.SerialNo
, p.Name
, c.Cost
, ci.DataDate
, ci.Data
,
FROM install i
JOIN product p USING (ProductId)
JOIN counter c USING (InstallId)
JOIN counter_item ci USING (CounterId)
WHERE i.ClientId LIKE $clientId
AND MONTH(ci.DataDate) BETWEEN $mStart AND $mEnd
";
This select works but it retrieves all records between the starting date and finishing date.
I tried, to get the top results and figured I would use A UNION ALL to combine with the bottom results (ci.DataDate ASC), but it's not working. I only get the first record encounter.
GROUP BY i.SerialNo
ORDER BY ci.DataDate DESC
It's like ORDER BY has no effect at all.
In counter_item you find the first and last DataDate per CounterId for the time range. So find these first by aggregation and use this information in order to join the desired records:
SELECT i.SerialNo,
p.Name,
c.Cost,
ci.DataDate,
ci.Data
FROM install i
JOIN product p ON p.ProductId = i.ProductId
JOIN counter c ON c.InstallId = i.InstallId
JOIN
(
SELECT CounterId, MIN(DataDate) AS MinDate, MAX(DataDate) AS MaxDate
FROM counter_item
WHERE MONTH(DataDate) BETWEEN $mStart AND $mEnd
GROUP BY CounterId
) minmax ON minmax.CounterId = c.CounterId
JOIN counter_item ci ON ci.CounterId = minmax.CounterId
AND ci.DataDate IN (minmax.MinDate, minmax.MaxDate)
WHERE i.ClientId LIKE $clientId
ORDER BY i.SerialNo, ci.DataDate
You could do it in next way, here is just general idea of how that could be done:
select * from table
where
([row] = (select max([row]) from table ) or
[Date] = (select min([row]) from table ))
You may also be able to use a cross apply. Something like this, untested rough sample:
SELECT i.SerialNo,
p.Name,
c.Cost,
MIN(ci.DataDate) as MinDate,
b.MaxDate,
ci.Data,
FROM install i
CROSS APPLY (SELECT
MAX(ci.DataDate) as MaxDate
FROM install
JOIN counter_item ci USING (CounterId)
WHERE i.ClientId LIKE $clientId
AND MONTH(ci.DataDate) BETWEEN $mStart AND $mEnd) b
WHERE i.ClientId LIKE $clientId
AND MONTH(ci.DataDate) BETWEEN $mStart AND $mEnd
GROUP BY i.SerialNo
ORDER BY ci.DataDate DESC
The following query always outputs SUM for all rows instead of per userid. Not sure where else to look. Please help.
SELECT * FROM assignments
LEFT JOIN (
SELECT SUM(timeworked) AS totaltimeworked
FROM time_entries
) assignments ON (userid = assignments.userid AND ticketid = ?)
WHERE ticketid = ?
ORDER BY assigned,scheduled
If you want to keep the SELECT *, you would have to add a group by clause in the subquery. Something like this
SELECT * FROM assignments
LEFT JOIN (
SELECT SUM(timeworked) AS totaltimeworked
FROM time_entries
GROUP BY userid
) time_entriesSummed ON time_entriesSummed.userid = assignments.userid
WHERE ticketid = ?
ORDER BY assigned,scheduled
But a better way would be to change the SELECT * to instead select the fields you want a add a group by clause directly. Something like this
SELECT
assignments.id,
assignments.assigned,
assignments.scheduled,
SUM(time_entries.timeworked) AS totalTimeworked
FROM assignments
LEFT JOIN time_entries
ON time_entries.userid = assignments.userid
GROUP BY assignments.id, assignments.assigned, assignments.scheduled
Edit 1
Included table names in query 2 as mentioned in chameera's comment below
I have written an sql statement that besides all the other columns should return the number of comments and the number of likes of a certain post. It works perfectly when I don't try to get the number of times it has been shared too. When I try to get the number of time it was shared instead it returns a wrong number of like that seems to be either the number of shares and likes or something like that. Here is the code:
SELECT
[...],
count(CS.commentId) as shares,
count(CL.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN
account A ON A.id = `AS`.accountId
INNER JOIN
comment C ON C.accountId = A.id
LEFT JOIN
commentLikes CL ON C.commentId = CL.commentId
LEFT JOIN
commentShares CS ON C.commentId = CS.commentId
GROUP BY
C.time
ORDER BY
year, month, hour, month
Could you also tell me if you think this is an efficient SQL statement or if you would do it differently? thank you!
Do this instead:
SELECT
[...],
(select count(*) from commentLikes CL where C.commentId = CL.commentId) as shares,
(select count(*) from commentShares CS where C.commentId = CS.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN account A ON A.id = `AS`.accountId
INNER JOIN comment C ON C.accountId = A.id
GROUP BY C.time
ORDER BY year, month, hour, month
If you use JOINs, you're getting back one result set, and COUNT(any field) simply counts the rows and will always compute the same thing, and in this case the wrong thing. Subqueries are what you need here. Good luck!
EDIT: as posted below, count(distinct something) can also work, but it's making the database do more work than necessary for the answer you want to end up with.
Quick fix:
SELECT
[...],
count(DISTINCT CS.commentId) as shares,
count(DISTINCT CL.commentId) as numberOfLikes
Better approach:
SELECT [...]
, Coalesce(shares.numberOfShares, 0) As numberOfShares
, Coalesce(likes.numberOfLikes , 0) As numberOfLikes
FROM [...]
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfShares
FROM commentShares
GROUP
BY commentId
) As shares
ON shares.commentId = c.commentId
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfLikes
FROM commentLikes
GROUP
BY commentId
) As likes
ON likes.commentId = c.commentId
I'm essentially trying to obtain a resultset with each employee's current title. I'd like to create a view from this for later use, but I find I'm being stumped, and likely missing a simple solution. Here's the query in question, and thanks in advance!
select * from
(SELECT
appointment.employee_id,
title.`name` as title_name
FROM
appointment
INNER JOIN appointment_title ON appointment.id = appointment_title.appointment_id
INNER JOIN title ON appointment_title.title_id = title.id
order by appointment_title.effective_date DESC) tmp group by employee_id
Updated:
SELECT
appointment.employee_id ,
( SELECT title.`name`
FROM appointment_title
INNER JOIN title
ON appointment_title.title_id = title.id
WHERE appointment.id = appointment_title.appointment_id
ORDER BY appointment_title.effective_date DESC
LIMIT 1
) AS title_name
FROM appointment
GROUP BY appointment.employee_id
Another option is to break up the query into two views. The first view will contain the derived table subquery, and the second will simply select from that one:
CREATE VIEW vwEmployee_Inner AS
SELECT
appointment.employee_id,
title.`name` as title_name
FROM
appointment
INNER JOIN appointment_title ON appointment.id = appointment_title.appointment_id
INNER JOIN title ON appointment_title.title_id = title.id
order by appointment_title.effective_date DESC
And then your original view becomes:
CREATE VIEW vwEmployee AS
SELECT * FROM vwEmployee_Inner GROUP BY employee_id