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.
I have one table with the following columns and sample values:
[test]
ID | Sample | Org | EmployeeNumber
1 100 6513241
2 200 3216542
3 300 5649841
4 100 9879871
5 200 6546548
6 100 1116594
My example count query based on [test] returns these sample values grouped by Org:
Org | Count of EmployeeNumber
100 3
200 2
300 1
My question is can I use this count to update test.Sample to 'x' for the top 3 records of Org 100, the top 2 records of Org 200, and the top 1 record of Org 300? It does not matter which records are updated, as long as the number of records updated for the Org = the count of EmployeeNumber.
I realize that I could just update all records in this example but I have 175 Orgs and 900,000 records and my real count query includes an iif that only returns a partial count based on other columns.
The db that I am taking over uses a recordset and loop to update. I am trying to write this in one SQL update statement. I have tried several variations of nested select statements but can't quite figure it out. Any help would save my brain from exploding. Thanks!
Assuming, that id is the unique ID of the row, you could use a correlated subquery to select the count of row IDs of the rows sharing the current organization, that are less than or equal to the current row ID and check, that this count is less than or equal to the number of records from that organization you want to designate.
For example to mark 3 records of the organization 100 you could use:
UPDATE test
SET sample = 'x'
WHERE org = 100
AND (SELECT count(*)
FROM test t
WHERE t.org = test.org
AND t.id <= test.id) <= 3;
And analog for the other cases.
(Disclaimer: I don't have access to Access (ha, ha, pun), so I could not test it. But I guess it's basic enough, to work in almost every DBMS, also in Access.)
I have two tables that I would like to make into one table.
TABLE WASP_COLOR1
ID NAME COLOR CODE
1 WASP01 RED RD
2 WASP04 RED RD
3 WASP19 BLUE BL
TABLE WASP_COLOR2
ID NAME SIZE CODE
1 WASP01 6 RD
2 WASP13 10 BL
3 WASP22 4 BL
I'm a novice and I need clear direction on how to obtain these results. (I want the duplicates merged.)
TABLE WASP_COLOR1
ID NAME COLOR SIZE CODE
1 WASP01 RED 6 RD
2 WASP04 RED RD
3 WASP19 BLUE BL
4 WASP13 10 BL
5 WASP22 4 BL
I tried the following:
SELECT
distinct wasp_color2.name, wasp_color2.size,
wasp_color2.code, wasp_color1.name, wasp_color1.color,
wasp_color1.code
INTO
wasp_color1
FROM
wasp_color2, wasp_color1;
Received error
I tried:
SELECT
distinct wasp_color2.name, wasp_color2.size, wasp_color2.code,
wasp_color1.name, wasp_color1.color, wasp_color1.code
INTO
test
FROM
wasp_color2, wasp_color1;
Received 9 rows instead of 5
I tried:
SELECT
name.wasp_color1, name.wasp_color2, color, size,
code.wasp_color1, code.wasp_color2
INTO
test
FROM wasp_color2, wasp_color1;
This asks for a parameter value, which is a manual entry and cumbersome
I tried:
SELECT
coalesce name.wasp_color1, name.wasp_color2, color,
size, code.wasp_color1, code.wasp_color2
INTO
test
FROM
wasp_color2, wasp_color1 full join;
Received error
Perhaps something like this as MS access doesn't support full outer joins.
What this does is generate two data sets one for wasp_Color1 and those records that match in wasp_Color2 and vice-versa. and then combine's those results into one data set eliminating the duplicates.
For a better understanding of joins: see https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Select WC1.Name, WC1.Color, WC2.Size, WC1.Code
FROM wasp_Color1 wc1
LEFT JOIN wasp_color2 wc2
on wc1.Name = WC2.Name
and wc1.code = wc2.code
UNION
Select WC2.Name, WC1.Color, WC2.Size, WC2.Code
FROM wasp_Color1 wc1
RIGHT JOIN wasp_color2 wc2
on wc1.Name = WC2.Name
and wc1.code = wc2.code
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
I have a table that holds allocations of problem reports (PRs) as follows:
TABLE "ALLOCATIONS"
ALLOCATIONID PRID DATEALLOCATED ENG_ID
1 401 20-SEP-06 10.48.00 1
2 401 20-SEP-06 10.48.00 2
3 401 20-SEP-06 10.48.00 2
4 402 20-SEP-06 12.35.00 1
5 402 20-SEP-06 12.43.00 1
6 402 20-SEP-06 13.43.00 2
7 700 14-OCT-12 13.30.05 1
8 700 14-OCT-12 13.30.35 2
9 700 14-OCT-12 14.30.35 2
The most recent allocation determines which engineer the PR is now assigned to. I want to find all the PRs that are assigned to engineer 2 for example.
So I look for the most recent allocation for each PRID, check the ENG_ID, then pull out the information from this table if the ENG_ID is correct.
This table contains the actual PR descriptions (and other info omitted here for clarity).
TABLE "PROBLEMS"
PRID TITLE
401 Something
402 Something
700 Something
To do this I have used the DATEALLOCATED field as follows:
SELECT PRID, TITLE FROM PROBLEMS p WHERE p.PRID IN
(
SELECT GROUPEDALLOC.PRID FROM allocations alloc INNER JOIN
(
SELECT PRID, MAX(DATEALLOCATED) AS MaxAllocationDate
FROM allocations
GROUP BY PRID
)
groupedAlloc ON alloc.PRID = groupedAlloc.PRID
AND ALLOC.DATEALLOCATED = groupedAlloc.MaxAllocationDate
AND ENG_ID = 2
)
ORDER BY PRID DESC;
Now this works fine for records 7,8,9 above which were inserted with a long date format that includes the seconds, however for the older records which didn't log the seconds this will obviously not work. For these records I want to fall back on the allocationID (which may or may not be sequential obviously - however it is a last resort and better than nothing).
My question is, how do I modify my query to perform this extra condition on the DATEALLOCATED (i just want to see if they are all equal for a particular PRID), and then use the ALLOCATIONID instead?
I am using OracleXE but I want to stick to standard SQL if possible.
Does this do it for you ?
WITH
BY_DATE
AS (SELECT PRID, MAX (DATEALLOCATED) AS MAXDATE FROM ALLOCATIONS GROUP BY PRID),
BY_ALLOC
AS (SELECT A.PRID, MAXDATE, MAX (ALLOCATIONID) AS MAXALLOC
FROM ALLOCATIONS A JOIN BY_DATE B ON
A.PRID = B.PRID AND
A.DATEALLOCATED = B.MAXDATE
GROUP BY A.PRID, MAXDATE)
SELECT A.PRID, A.ENG_ID
FROM ALLOCATIONS A JOIN BY_ALLOC B ON
A.ALLOCATIONID = B.MAXALLOC;