Error when COUNT after MAX? - sql

I have a table Act in a medical database :
IDAct Historic IDPatient
1 2001-01-01 1
1 2001-01-02 1
2 2001-01-01 2
3 2001-01-03 1
I would like to compute the column IDActPerPatient:
IDAct Historic IDPatient IDActPerPatient
1 2001-01-02 1 1
2 2001-01-01 2 1
3 2001-01-03 1 2
The Act table contains Acts with the historic of every modification of an act. (the index is the pair (IDAct,Historic)).
So I'm interested in the last modified acts:
SELECT A.IDActe, MAX(Historic) AS Historic FROM Act A GROUP BY IDAct
Now, I'd like to number the Acts per patient. So I count the number of acts with an IDAct less or equal for one patient.
I have created a view LastAct with the previous request and I try this one :
SELECT DA1.*, COUNT(*) AS IDActPerPatient
FROM LastAct DA1
INNER JOIN LastAct DA2 ON DA1.IDPatient = DA2.IDPatient
AND DA2.IDActe >= DA1.IDAct
GROUP BY DA1.IDAct
...which does not work!
I get large numbers in IDActPerPatient when an act has several version in historic (for a patient who has 1 act in 3 versions I have 81).
Do you have an idea where the problem comes from ?

SELECT A.IDActe,
MAX(Historic) AS Historic,
(SELECT COUNT(DISTINCT IDAct) FROM ACT B WHERE A.IDPatient=B.IDPatient)
FROM Act A
GROUP BY IDAct
?

Thank you! I don't use select in the select enough but It's really helpful here!
here is the fixed request:
SELECT A.IDAct, A.IDPatient,
MAX(Historic) AS Historic,
(SELECT COUNT(DISTINCT IDAct) FROM Act B WHERE A.IDPatient=B.IDPatient
AND A.IDAct>=B.IDAct) AS IDActPerPatient
FROM Act A
GROUP BY IDAct

Related

How do I stop my query from pulling duplicates?

Yes, I know this seems simple:
SELECT DISTINCT(...)
Except, it apparently isn't
Here is my actual Query:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS,
IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune,
IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical,
IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther,
IIf([DecReason]=7,1,0) AS YesAlready
FROM
EmployeeInformation
INNER JOIN (CompletedTrainings
LEFT JOIN DeclinationReasons ON CompletedTrainings.DecReason = DeclinationReasons.ReasonID)
ON EmployeeInformation.ID = CompletedTrainings.Employee
GROUP BY
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No"),
IIf([DecReason]=1,1,0),
IIf([DecReason]=2,1,0),
IIf([DecReason]=3,1,0),
IIf([DecReason]=4,1,0),
IIf([DecReason]=5,1,0),
IIf([DecReason]=6,1,0),
IIf([DecReason]=7,1,0)
HAVING
((((EmployeeInformation.Active) Like -1)
AND ((CompletedTrainings.DecShotDate + 365 >= DATE())
OR (CompletedTrainings.DecShotDate IS NULL))));
This is Joining a few tables (obviously) in order to get a number of records. The problem is that if someone is duplicated on the table with a NULL in one of the date fields, and a date in another field, it pulls both the NULL and the DATE, or pulls multiple NULLS it might pull multiple dates but those are not present right at the moment.
I need the Nulls, they are actual data in this particular case, but if someone has a date and a NULL I need to pull only the newest record, I thought I could add MAX(RecordID) from the table, but that didn't change the results of the query either.
That code:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
MAX(CompletedTrainings.RecordID),
CompletedTrainings.DecShotDate
...
And it returned the same issue, Duplicated EmployeeInformation.ID with different DecShotDate values.
Currently it returns:
ID
Active
DecShotDate
etc. x a bunch
1
-1
date date
whatever goes
2
-1
in these
2
-1
date date
columns
These are being used in a report, that is to determine the total number of employees who fit the criteria of the report. The NULLs in DecShotDate are needed as they show people who did not refuse to get a flu vaccine in the current year, while the dates are people who did refuse.
Now I have come up with one simple solution, I could add a column to the CompletedTrainings Table that contains a date or other value, and add that to the HAVING statement. This might be the right solution as this is a yearly training questionnaire that employees have to fill out. But I am asking for advice before doing this.
Am I right in thinking I need to add a column to filter by so that older data isn't being pulled, or should I be able to do this by pulling recordID, and did I just bork that part of the query up?
Edited to add raw table views:
EmployeeInformation Table:
ID
Last
First
empID
Active
Termdate
DoH
Title
PT/FT/PD
PI
1
Doe
Jane
982
-1
date
Sr
PD
X
2
Roe
John
278
0
date
date
Jr
PD
X
3
Moe
Larry
1232
-1
date
Sr
FT
X
4
Zoe
Debbie
1424
-1
date
Sr
PT
X
DeclinationReasons Table:
ReasonID
Reason
1
Allergy
2
Already got it
3
Illness
CompletedTrainings Table:
RecordID
Employee
Training
...
DecShotdate
DecShotLocation
DecShotReason
DecExp
1
1
4
date
location
2
text
2
1
4
3
2
4
4
3
4
date
location
3
text
5
3
4
date
location
1
text
6
4
4
After some serious soul searching, I decided to use another column and filter by that.
In the end my query looks like this:
SELECT *
FROM (
(
SELECT RecordID, DecShotDate, DecShotLocation, DecReason, DecExplanation, Employee,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS, IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune, IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical, IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther, IIf([DecReason]=7,1,0) AS YesAlready
FROM CompletedTrainings WHERE (CompletedDate > DATE() - 365 ) AND (Training = 69)) AS T1
LEFT JOIN
(
SELECT ID, Active FROM EmployeeInformation) AS T2 ON T1.Employee = T2.ID)
LEFT JOIN
(
SELECT Reason, ReasonID FROM DeclinationReasons) AS T3 ON T1.DecReason = T3.ReasonID;
This may not have been the best solution, but it did exactly what I needed. Which is to get the information by latest entry into the database.
Previously I had tried to use MAX(), DISTINCT(), etc. but always had a problem of multiple records being retrieved. In this case, I intentionally SELECT the most recent records first, then join them to the results of the next query, and so on. Until I have all the required data for my report.
I write this in hopes someone else finds it useful. Or even better if someone tells me why this is wrong, so as to improve my own skills.

SQL Query Count results as zero event record is not exist

I have an issue to an SQL Query (Oracle database).
I have two tables. One table is "ACCIDENTS " and the other is "REASONS". This second is table has some predefined default values.
- REASONS -
Reason 1
Reason 2
Reason 3
Reason 4
Now in the ACCIDENTS table we insert some accidents and reasons from the previous table like below
- ACCIDENTS -
Accident 1 - Reason 1
Accident 2 - Reason 1
Accident 3 - Reason 4
All I want to get the count of accidents GROUP BY all 4 reasons even if a reason does not exist in ACCIDENTS table. In this case I want to get Count = 0 like below:
REASONS COUNT (of Accidents)
Reason 1 2
Reason 2 0
Reason 3 0
Reason 4 1
Unsuccessfully I have already tried different type of JOIN tables but I don't get as results Reason 2 and Reason 3 because they don't exist in ACCIDENTS table. Every time the result is:
REASONS COUNT (of Accidents)
Reason 1 2
Reason 4 1
Any solutions/thoughts ?
Thanks in advance!
UPDATE !
This is the query:
SELECT R.REASON_NAME AS REASON, COUNT(A.ID) AS COUNT_OF_ACCIDENTS
FROM ACCIDENTS A
RIGHT JOIN REASONS R ON R.ID = A.REASON_ID
WHERE EXTRACT(YEAR FPOM A.DATE_OF_ACCIDENT) = 2017
GROUP BY R.REASON_NAME
If i remove the WHERE statement then I get all REASONS correctly but the Where for Year in Accidents table is mandatory.
You want a left join and aggregation:
select r.reason, count(a.reason)
from reasons r left join
accidents a
on r.reason = a.reason and
a.date_of_accident >= date '2017-01-01' and
a.date_of_accident < date '2018-01-01'
group by r.reason;

Join check view with a calendar view

I have two views. One with checks:
Check_Id Issued_Date Cleared_Date Amount
1 2017.01.03 2017.02.04 100
2 2017.03.03 2017.04.04 100
3 2017.08.03 100
...
And another is just a calendar:
Day
2001.01.01
2001.01.02
2001.01.03
...
2100.12.31
I need a scaffold view for Tableau. What i'd like to achieve is, for every check, have a record in the dates between Issued date to the cleared date. If there is no cleared date, just go to the end of times (2100.12.31 in this case).
Ie, for the Check_id 1:
Day Check_ID
2017.01.03 1
2017.01.03 1
2017.01.03 1
2017.01.03 1
...
2017.02.04 1
2017.08.03 3
2017.08.04 3
2017.08.05 3
2017.08.06 3
...
2100.12.31 3
Any tip or stuff i'd read to get it? Thanks!
This is a non-equijoin:
select ca.day, c.check_id
from checks c join
calendar ca
on ca.day >= c.issued_date and
(c.cleared_date is null or c.cleared_date >= ca.date);

access SQL count results using multiple sub queries against one table

I am using Access with a table having over 200k rows of data. I am looking for counts on a column which is broken down by job descriptions. For example, I want to return the total count (id) for a location where a person is status = "active" and position like "cook" [should equal 20] also another output where I get a count (id) for the same location where a person is status = "active" and position = "Lead Cook" [should equal 5]. So, one is a partial of the total population.
I have a few others to do just like this (# Bakers, # Lead Bakers...). How can I do this with one grand query/subquery or one query for each grouping.
My attempt is more like this:
SELECT
a.location,
Count(a.EMPLOYEE_NUMBER) AS [# Cook Total], --- should equal 20
(SELECT count(b.EMPLOYEE_ID) FROM Table_abc AS b where b.STATUS="Active Assignment" AND b.POSITION Like "*cook*" AND b.EMPLOYEE_ID=a.EMPLOYEE_ID) AS [# Lead Cook], --- should equal 5
FROM Table_abc AS a
ORDER BY a.location;
Results should be similar to:
Location Total Cooks Lead Cooks Total Bakers Lead Bakers
1 20 4 15 2
2 45 7 12 2
3 22 2 16 1
4 19 2 17 2
5 5 1 9 1
Try using conditional aggregation -- no need for sub queries.
Something like this should work (although I may not understand your desired results completely):
select location,
count(EMPLOYEE_NUMBER) as CookTotal,
sum(IIf(POSITION Like "*cook*",1,0)) as AllCooks,
sum(IIf(POSITION = "Lead Cook",1,0)) as LeadCooks
from Table_abc
where STATUS="Active Assignment"
group by location

Progressive count using a query?

I use this query to
SELECT userId, submDate, COUNT(submId) AS nSubms
FROM submissions
GROUP BY userId, submDate
ORDER BY userId, submDate
obtain the total number of submissions per user per date.
However I need to have the progressive count for every user so I can see how their submissions accumulate over time.
Is this possible to implement in a query ?
EDIT: The obtained table looks like this :
userId submDate nSubms
1 2-Feb 1
1 4-Feb 7
2 1-Jan 4
2 2-Jan 2
2 18-Jan 1
I want to produce this :
userId submDate nSubms progressive
1 2-Feb 1 1
1 4-Feb 7 8
2 1-Jan 4 4
2 2-Jan 2 6
2 18-Jan 1 7
EDIT 2 : Sorry for not mentioning it earlier, I am not allowed to use :
Stored procedure calls
Update/Delete/Insert/Create queries
Unions
DISTINCT keyword
as I am using a tool that doesn't allow those.
You can use a self-join to grab all the rows of the same table with a date before the current row:
SELECT s0.userId, s0.submDate, COUNT(s0.submId) AS nSubms, COUNT (s1.submId) AS progressive
FROM submissions AS s0
JOIN submissions AS s1 ON s1.userId=s0.userId AND s1.submDate<=s0.submDate
GROUP BY s0.userId, s0.submDate
ORDER BY s0.userId, s0.submDate
This is going to force the database to do a load of pointless work counting all the same rows again and again though. It would be better to just add up the nSubms as you go down in whatever script is calling the query, or in an SQL variable, if that's available in your environment.
The Best solution for this is to do it at the client.
It's the right tool for the job. Databases are not suited for this kind of task
Select S.userId, S.submDate, Count(*) As nSubms
, (Select Count(*)
From submissions As S1
Where S1.userid = S.userId
And S1.submDate <= S.submDate) As TotalSubms
From submissions As S
Group By S.userid, S.submDate
Order By S.userid, S.submDate