Including records that are missing in another dataset - sql

I'm trying to do something along the lines of a WHERE NOT EXISTS or WHERE NOT IN, but am struggling with the syntax.
This is the results set I've got so far, let's called it PlanActStaff:
SELECT
CTE_PlanStaff.RegisterID,
CTE_PlanStaff.TT_ActivityDate,
CTE_PlanStaff.TT_ActivityTime,
CTE_PlanStaff.TT_StaffID,
CTE_ActStaff.ActStaffID
FROM
CTE_PlanStaff
INNER JOIN
CTE_ActStaff
ON
CTE_PlanStaff.RegisterID = CTE_ActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = CTE_ActStaff.ActSessionDate
AND
CTE_PlanStaff.TT_ActivityTime = CTE_ActStaff.ActSessionStartTime
For each record in this result set I want the query to go back and check my CTE_PlanStaff CTE to see whether the ActStaffID exists for the current combination of RegisterID, TT_ActivityDate and TT_ActivityTime in CTE_PlanStaff.
So for example, if a record being checked in PlanActStaff looked like this:
| RegisterID | TT_ActivityDate | TT_ActivityTime | TT_StaffID | ActStaffID |
|------------|-----------------|-----------------|------------|------------|
| 98688 | 2016-01-04 | 11:20 | 2453 | 2067 |
CTE_PlanStaff would then be filtered on the same combination of RegisterID, TT_ActivityDate and TT_ActivityTime, so CTE_PlanStaff might then have these records to compare:
| RegisterID | TT_ActivityDate | TT_ActivityTime | TT_StaffID |
|------------|-----------------|-----------------|------------|
| 98688 | 2016-01-04 | 11:20 | 2500 |
| 98688 | 2016-01-04 | 11:20 | 2453 |
I'd then like the ActStaffID value of 2067 checked against each TT_StaffID in the filtered CTE_PlanStaff and if the ActStaffID isn't listed to leave that record showing in my PlanActStaff query.
I've tried to adapt PlanActStaff as follows...
SELECT *
FROM
(
SELECT
CTE_PlanStaff.RegisterID,
CTE_PlanStaff.TT_ActivityDate,
CTE_PlanStaff.TT_ActivityTime,
CTE_PlanStaff.TT_StaffID,
CTE_ActStaff.ActStaffID
FROM
CTE_PlanStaff
INNER JOIN
CTE_ActStaff
ON
CTE_PlanStaff.RegisterID = CTE_ActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = CTE_ActStaff.ActSessionDate
AND
CTE_PlanStaff.TT_ActivityTime = CTE_ActStaff.ActSessionStartTime
) PlanActStaff
WHERE
ActStaffID NOT IN (
SELECT *
FROM
CTE_PlanStaff
WHERE
CTE_PlanStaff.RegisterID = PlanActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = PlanActStaff.TT_ActivityDate
AND
CTE_PlanStaff.TT_ActivityTime = PlanActStaff.TT_ActivityTime
)
...but I get the following error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS.
I started looking at WHERE NOT EXISTS, but I can't figure out how to both filter CTE_PlanStaff against the current record and then check the staffID fields.

WHERE
ActStaffID NOT IN (
SELECT *
FROM
CTE_PlanStaff
WHERE
CTE_PlanStaff.RegisterID = PlanActStaff.RegisterID
AND
CTE_PlanStaff.TT_ActivityDate = PlanActStaff.TT_ActivityDate
AND
CTE_PlanStaff.TT_ActivityTime = PlanActStaff.TT_ActivityTime
)
you should select only one field to be compared against 'ActStaffID'

Related

Update referencing on subquery (sqlite)

I have a table with md5 sums for files and use the following query to find the files which exist in one hashing-run and not in the other (oldt vs newt):
SELECT *
FROM md5_sums as oldt
WHERE NOT EXISTS (SELECT *
FROM md5_sums as newt
WHERE oldt.file = newt.file
and oldt.relpath = newt.relpath
and newt.starttime = 234)
and oldt.starttime = 123
now I want to put a flag in an extra column with an update clause, like
update md5_sums
set only_in_old = 'X'
where
and there I want a reference to the upper query as subquery, but i cannot find a proper way. Is there a possibility to use the results from the upper query for the where clause from the update-query?
(I added now some Table Screenshots with simple Table Data)
Table Description
Table Data before UPDATE
desired Table Data after UPDATE
SQLite does not support aliasing the updated table.
In your case you don't need that.
You can use the table's name md5_sums inside the subquery since you aliased the table of the SELECT statement as newt.
UPDATE md5_sums
SET only_in_old = 'X'
WHERE NOT EXISTS (
SELECT 1 FROM md5_sums AS newt
WHERE md5_sums.file = newt.file
AND md5_sums.relpath = newt.relpath
AND newt.starttime = 234
)
AND starttime = 123
See the demo.
Results:
| file | relpath | starttime | only_in_old |
| ------- | -------- | --------- | ----------- |
| abc.txt | /var/tmp | 123 | |
| abc.txt | /var/tmp | 234 | |
| def.txt | /tmp | 123 | X |
| xyz.txt | /tmp | 234 | |
I hope this helps you in converting the select statement into an update statement,
UPDATE md5_sums
SET only_in_old = 'X'
WHERE NOT EXISTS (SELECT *
FROM md5_sums newt
WHERE file = newt.file
and relpath = newt.relpath
and newt.starttime = 1551085649.7764235)
and starttime = 1551085580.009046

Select and count in the same query on two tables

I've got these two tables:
___Subscriptions
|--------|--------------------|--------------|
| SUB_Id | SUB_HotelId | SUB_PlanName |
|--------|--------------------|--------------|
| 1 | cus_AjGG401e9a840D | Free |
|--------|--------------------|--------------|
___Rooms
|--------|-------------------|
| ROO_Id | ROO_HotelId |
|--------|-------------------|
| 1 |cus_AjGG401e9a840D |
| 2 |cus_AjGG401e9a840D |
| 3 |cus_AjGG401e9a840D |
| 4 |cus_AjGG401e9a840D |
|--------|-------------------|
I'd like to select the SUB_PlanName and count the rooms with the same HotelId.
So I tried:
SELECT COUNT(*) as 'ROO_Count', SUB_PlanName
FROM ___Rooms
JOIN ___Subscriptions
ON ___Subscriptions.SUB_HotelId = ___Rooms.ROO_HotelId
WHERE ROO_HotelId = 'cus_AjGG401e9a840D'
and
SELECT
SUB_PlanName,
(
SELECT Count(ROO_Id)
FROM ___Rooms
Where ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
) as ROO_Count
FROM ___Subscriptions
WHERE SUB_HotelId = 'cus_AjGG401e9a840D'
But I get empty datas.
Could you please help ?
Thanks.
You need to use GROUP BY whenever you do some aggregation(here COUNT()). Below query will give you the number of ROO_ID only for the SUB_HotelId = 'cus_AjGG401e9a840D' because you have this condition in WHERE. If you want the COUNTs for all Hotel_IDs then you can simply remove the WHERE filter from this query.
SELECT s.SUB_PlanName, COUNT(*) as 'ROO_Count'
FROM ___Rooms r
JOIN ___Subscriptions s
ON s.SUB_HotelId = r.ROO_HotelId
WHERE r.ROO_HotelId = 'cus_AjGG401e9a840D'
GROUP BY s.SUB_PlanName;
To be safe, you can also use COUNT(DISTINCT r.ROO_Id) if you don't want to double count a repeating ROO_Id. But your table structures seem to have unique(non-repeating) ROO_Ids so using a COUNT(*) should work as well.

MS Access 2013 - How to perform a SQL Update with id based on MAX date from another table?

First time posting, please forgive my newbieness!
In MS Access 2013, How can I update the Actions table's 'LatestRequest' column with the 'id' from the IncomingRequests table by using only for the latest RequestDate for each Scan Result ID ?
Note that there can be duplicate Scan Result IDs in IncomingRequests, but the date will always be different.
Actions Table:
id (primary key) | Scan Result ID | LatestRequest | other-misc-columns...
1 | 123456 | (blank)
2 | 666666 | (blank)
3 | 789789 | (blank)
4 | 888888 | (blank) (this record won't change)
5 | 999222 | 987 (this record won't change)
IncomingRequests Table:
id (primary key) | RequestDate | Scan Result ID | other-misc-columns...
201 | 5/9/2016 | 123456
202 | 4/12/2016 | 123456
203 | 5/7/2016 | 666666
204 | 5/8/2016 | 666666
205 | 5/9/2016 | 789789
What I want to see:
Action Table:
id (primary key) | Scan Result ID | LatestRequest | other-misc-columns...
1 | 123456 | 201
2 | 666666 | 204
3 | 789789 | 205
4 | 888888 | (blank)
5 | 999222 | 987
I've tried creating a subquery for the max date, and updating the Actions table, but run into "Operation must use an updateable query".
UPDATE Actions INNER JOIN (SELECT t1.*
FROM
IncomingRequests t1
INNER JOIN
(
SELECT [Scan Result ID], MAX([DateFromIT]) AS MaxDate
FROM IncomingRequests
GROUP BY [Scan Result ID]
) t2
ON t1.[Scan Result ID]=t2.[Scan Result ID]
AND t1.[RequestDate]=t2.MaxDate
) AS ij ON Actions.[Scan Result ID] = ij.[Scan Result ID]
SET LatestRequest = ij.id
The alternate version I have (below) checks using the Request table primary key id, and this works, except that I really need it by latest date, not highest id.
UPDATE Actions
INNER JOIN IncomingRequests ON Actions.[Scan Result ID] = IncomingRequests.[Scan Result ID]
SET Actions.latestrequest = IncomingRequests.id
WHERE IncomingRequests.id=
(SELECT MAX(IncomingRequests.id)
FROM IncomingRequests
WHERE Actions.[Scan Result ID] = IncomingRequests.[Scan Result ID]
GROUP BY IncomingRequests.[Scan Result ID] );
I've ran into many dead ends trying to follow other answers from this site, or errors in MS Access that others didn't seem to get. Any assistance appreciated.
Thanks so much! =)
Try this and let me know if this solved your problem
update Actions set Actions.LatestRequest = t2.id
from Actions
inner join (select id,ScanResultID from IncomingRequests where RequestDate
in (select MAX(RequestDate) from IncomingRequests group by ScanResultID))
t2 on Actions.ScanResultID = t2.ScanResultID
I eventually resolved by creating a Sub module in VBA to do the following:
DROP a temp table.
Perform a SELECT with the MAX date into a temp table.
Perform an UPDATE with an INNER JOIN to the temp table.
DROP the temp table.
Ugly, but it's the only way I could get it to work.

Multiple select or distinct

I am new to sql so looking for a little help - got the first part down however I am having issues with the second part.
I got the three tables tied together. First I needed to tie tblPatient.ID = tblPatientVisit.PatientID together to eliminate dups which works
Now I need to take those results and eliminate dups in the MRN but my query is only returning one result which is WRONG - LOL
Query
select
tblPatient.id,
tblPatient.firstname,
tblPatient.lastname,
tblPatient.dob,
tblPatient.mrn,
tblPatientSmokingScreenOrder.SmokeStatus,
tblPatientVisit.VisitNo
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
and tblPatient.ID in(
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I')
Actual Results:
ID | firstName | LastName | DOB | MRN | SmokeStatus | VisitNO
12 | Test Guy | Today | 12/12/1023 | 0015396 | Never Smoker | 0013957431
Desired Results:
90 | BOB | BUILDER | 02/24/1974 | 0015476 | Former Smoker | 0015476001
77 | DORA | EXPLORER | 06/04/1929 | 0015463 | Never Smoker | 0015463001
76 | MELODY | VALENTINE | 09/17/1954 | 0015461 | Current | 0015461001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Current | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Never Smoker | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Former Smoker | 0015415001
12 | Test Guy | Today | 12/12/1023 | 0015345 | Never Smoker | 0013957431
Anyone have any suggestions on how I go down to the next level and get all the rows with one unique MRN. From the data above I should have 5 in my list. Any help would be appreciated.
Thanks
If I had to guess -- The only thing that looks odd (but maybe it's OK) is that you're comparing patient.ID from your parent query to patient.mrn in the subquery.
Beyond that -- things to check:
(1)
Do you get all your patients with the inner query?
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I'
(2)
What is your patient type for the missing records? (Your filtering it to tblPatientVisit.PatientType = 'I' -- do the missing records have that patient type as well?)
Perhaps you need to invert the logic here. As in,
Select Distinct
patients.mrn1
From (select
tblPatient.id as id1,
tblPatient.firstname as firstname1,
tblPatient.lastname as lastname1,
tblPatient.dob as DOB1,
tblPatient.mrn as mrn1,
tblPatientSmokingScreenOrder.SmokeStatus as SmokeStatus1,
tblPatientVisit.VisitNo as VisitNo1,
tblPatientVisit.PatientType as PatientType1,
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
) as patients
where
isdate(patients.DOB1) = 1
and Convert(date,patients.DOB1) <'12/10/2000'
and patients.PatientType1 = 'I');
Cleaned it up a bit and I think they were right. MRN wont match patient id, at least not from your example data. You should not need an inner query. This query should give you what you want.
SELECT DISTINCT
p.id,
p.firstname,
p.lastname,
p.dob,
p.mrn,
s.SmokeStatus,
v.VisitNo
FROM
tblPatient p
JOIN tblPatientVisit v ON p.id = v.patientId
JOIN tblPatientSmokingScreenOrder s ON v.id = s.visitId
WHERE
isdate(p.DOB) = 1
AND CONVERT(date,p.DOB) <'12/10/2000'
AND v.PatientType = 'I'

Assistance with SQL multi-table query - returning duplicate results

We use an online project management system, and I'm trying to extend it somewhat.
It has the following tables of interest:
todo_itemStatus:
+--------------+-----------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------------------+----------------+
| itemStatusId | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| itemId | int(10) unsigned | NO | MUL | 0 | |
| statusDate | datetime | NO | | 0000-00-00 00:00:00 | |
| statusKey | tinyint(3) unsigned | NO | | 0 | |
| memberId | mediumint(8) unsigned | NO | | 0 | |
+--------------+-----------------------+------+-----+---------------------+----------------+
This table keeps track of when a task is complete, and also keeps the status of all task changes.
There's then a project table, and an 'item' (or task) table.
I basically want to be able to extract a list of projects, with details on the percentage of tasks complete. However, for now I'd be happy if I could just list each task in a project with details on whether they're complete.
As far as I'm aware, the best way to get the most recent status of a task is to choose an todo_itemStatus where the statusDate is the newest, or the itemStatusId is the largest whilst itemId equals the task I'm interested.
I tried a query like this:
<pre>
select todo_item.itemId, todo_item.title, todo_itemStatus.statusKey, todo_itemStatus.statusDate
from todo_item, todo_project, todo_itemStatus
where todo_item.projectId = todo_project.projectId
and todo_project.projectId = 13
and todo_itemStatus.itemId = todo_item.itemId
and todo_itemStatus.statusDate = (
select MAX(todo_itemStatus.statusDate)
from todo_itemStatus key1 where todo_itemStatus.itemId = key1.itemId);
</pre>
However, this yields all status updates with output like this:
+--------+-----------------------------------------------------------------------------+-----------+---------------------+
| itemId | title | statusKey | statusDate |
+--------+-----------------------------------------------------------------------------+-----------+---------------------+
| 579 | test complete item - delete me | 1 | 2009-07-28 13:04:38 |
| 579 | test complete item - delete me | 0 | 2009-07-28 14:12:12 |
+--------+-----------------------------------------------------------------------------+-----------+---------------------+
Which isn't what I want, as I only want one task entry returning with the statusKey / statusDate from the most recent entry in the todo_itemStatus table.
I know I've been a bit vague in my description, but I didn't want to write a massively long message. I can provide much more detail if necessary.
Please can someone suggest what I'm doing wrong? It's been a long time since I've done any real database stuff, so I'm a bit unsure what I'm doing wrong here...
Many thanks!
Dave
You should look into using the DISTINCT keyword (Microsoft SQL Server)
EDIT: I've just re-read your question and I think that the GROUP BY clause is more suited in this situation. You should read http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/, however essentially what you need to do is first select the columns that you are interested in using a GROUP BY clause:
SELECT todo_itemStatus.itemStatusId, MAX(todo_itemStatus.statusDate)
FROM todo_item, todo_project, todo_itemStatus
WHERE todo_item.projectId = todo_project.projectId
AND todo_itemStatus.itemId = todo_item.itemId
AND todo_project.projectId = 13
GROUP BY itemStatusId
We then self-join to this set of id's to get the rest of the columns we are interested in:
SELECT
todo_item.itemId,
todo_item.title,
todo_itemStatus.statusKey,
todo_itemStatus.statusDate
FROM todo_item
JOIN todo_itemStatus
ON todo_itemStatus.itemId = todo_item.itemId
JOIN
(SELECT todo_itemStatus.itemStatusId, MAX(todo_itemStatus.statusDate)
FROM todo_item, todo_project, todo_itemStatus
WHERE todo_item.projectId = todo_project.projectId
AND todo_itemStatus.itemId = todo_item.itemId
AND todo_project.projectId = 13
GROUP BY itemStatusId) AS x
ON todo_itemStatus.itemStatusId = x.itemStatusId
I've experimented some more and the following query does what I want:
select todo_item.itemId, todo_item.title, todo_itemStatus.statusKey, todo_itemStatus.statusDate from todo_itemStatus, todo_item where todo_item.itemId = todo_itemStatus.itemId and todo_item.projectId = 13 and todo_itemStatus.statusDate = (select MAX(status.statusDate) from todo_itemStatus as status where status.itemId = todo_item.itemId);
So I'm now happy. Thanks for all the help and the suggestions.
Dave.