MS Access: How do I find an employee with the latest date with "Working" or "Reinstated" status only? - sql

tbl_emp_mast
emp_no emp_last_name emp_first_name
1 smith john
2 doe jane
3 case justin
tbl_emp_st
emp_no st_date emp_st
1 10/01/2020 WORKING
1 10/05/2020 QUIT
1 10/10/2020 REINSTATED
2 10/07/2020 QUIT
3 10/02/2020 WORKING
For the purpose of the combo box in the form, I wanted only those employees who are currently working. So, there should be employees # 1 and 3 from the query result.
I tried this:
SELECT tbl_emp_mast.emp_no AS tbl_emp_mast_emp_no, tbl_emp_mast.emp_last_name & ", " & tbl_emp_mast.emp_first_name AS Employee, tbl_emp_st.st_date, tbl_emp_st.emp_st
FROM tbl_emp_mast INNER JOIN tbl_emp_st ON tbl_emp_mast.[emp_no] = tbl_emp_st.[emp_no];
Thank you.

Hmmm . . . I think you want the most recent emp_st. If so, then I think:
select es.*
from tbl_emp_st as es
where es.st_date = (select max(es2.st_date)
from tbl_emp_st as es2
where es2.emp_no = es.emp_no
) and
es.emp_st in ('WORKING', 'REINSTATED');

You should add a WHERE clause to check that the latest date for each tbl_emp_st is a row where emp_st is not equal to 'QUIT':
SELECT m.emp_no AS tbl_emp_mast_emp_no,
m.emp_last_name & ', ' & m.emp_first_name AS Employee,
s.st_date,
s.emp_st
FROM tbl_emp_mast AS m INNER JOIN tbl_emp_st AS s
ON m.emp_no = s.emp_no
WHERE s.st_date = (SELECT MAX(st_date) FROM tbl_emp_st WHERE emp_no = m.emp_no)
AND s.emp_st <> 'QUIT'
Results:
tbl_emp_mast_emp_no Employee st_date emp_st
1 smith, john 10/10/2020 REINSTATED
3 case, justin 10/02/2020 WORKING

Related

Update using joins by finding the previous value in sql

I have two tables and I have to update the address field in the emp table by looking up in the emphistory table with previous value i.e USA for employee John
Table emp
EId ename sal Address AccountId
-------------------------------
101 John 100 U X12
102 Peter 500 Null X13
Table emphistory
emphisid EId AccountId Address Date (use row_number to find the second record for that eid and accountid)
-----------------------------------------------------
1 101 X12 U 11-01-2020 09:45:00
2 102 X13 Null 11-01-2020 09:46:00
3. 101 X12 USA 11-01-2020 09:30:00
I have to join the tables with account id and eid.
This works in Postgresql & Sql Server
UPDATE emp
SET Address = hist.Address
FROM (
SELECT h.EId, h.AccountId, h.Address
, ROW_NUMBER() OVER (PARTITION BY h.EId, h.AccountId
ORDER BY h.Date DESC) AS Rn
FROM emphistory h
JOIN emp e
ON e.EId = h.EId
AND e.AccountId = h.AccountId
WHERE h.Address IS NOT NULL
) hist
WHERE emp.EId = hist.EId
AND hist.Rn = 2

SQL Query: New columns for data with some matching criteria

I'm working with a query that pulls data from a table and arranges it in a manner similar to below:
Query1
BldID UnitID Res1
1 201 John Smith
1 201 Jane Doe
1 202 Daniel Jones
1 202 Mark Garcia
2 201 Maria Lee
2 201 Paul Williams
2 201 Mike Jones
I'd like to modify the query output in SQL/Design so that each resident that shares a building / unit shows as a new column on the same row as shown below:
BldID UnitID Res1 Res2 Res3
1 201 John Smith Jane Doe
1 202 Daniel Jones Mark Garcia
2 201 Maria Lee Paul Williams Mike Jones
I apologize if this is crude/not enough information but any help would be greatly appreciated.
You can try using conditional aggregation
with cte as
(
select *, row_number() over(partition by BldID,UnitID order by Res1) as rn
from tablename
)
select BldID,UnitID,
max(case when rn=1 then Res1 end) as Res1,
max(case when rn=2 then Res1 end) as Res2,
max(case when rn=3 then Res1 end) as Res3
from cte
group by BldID,UnitID
So, drawing from a few different sources, this might work, try pasting this intoa query editor, and see if it'll run.
TRANSFORM MAX(Res1)
SELECT BldID, UnitID
, (
SELECT COUNT(T1.Marks)
FROM tableName AS T1
WHERE
T1.BldgID = T2.BldgID AND
T1.UnitID = T2.UnitID AND
T1.Res1 >= T2.Res1
) AS Rank, Res1
FROM tableName t2
GROUP BY BldID, UnitID
PIVOT Rank;
2 years late, but maybe I can add something, in Access we are surgeons operating with kitchen knifes, things must be done in the Access Way...
I tested it having this table UnitStudentBlock
BldID
UnitID
Res1
1
201
John Smith
1
201
Jane Doe
1
202
Daniel Jones
1
202
Mark Garcia
2
201
Maria Lee
2
201
Paul Williams
2
201
Mike Jones
2
201
Julian Gomes
As Access doesn't have row_number, first I created a table with an auto increment field so that we can have something like a row number:
CREATE TABLE TableWithId
(
Id COUNTER,
BldID INT,
UnitID INT,
Res1 VARCHAR(100),
ResNumber VARCHAR(100)
)
Then I inserted all the data from the initial table into this newly created table:
INSERT INTO TableWithId (BldID, UnitID, Res1)
SELECT *
FROM UnitStudentBlock
ORDER BY BldID,
UnitID
Then I updated everything using DCOUNT to have a row_number partitioned:
UPDATE TableWithId
SET ResNumber = 'Res' + Cstr(DCOUNT("*", "TableWithId", "ID >=" & [ID]
& " AND UnitId = " & [UnitId]
& " AND BldId = " & [BldId]))
And finally we can run the query that returns the data:
TRANSFORM MAX(Res1)
SELECT BldID, UnitID
FROM TableWithId
GROUP BY BldID, UnitID
PIVOT ResNumber

How to assign filters to row number () function in sql

I am trying to extract only single row after name = system in each case where the town is not Austin.
In case 1001 there are 8 rows, row # 4 is system, output should be only the row with Name=Terry and Date Moved=7/4/2019 (Next entry with town /= Austin)
Case Name Town Date Moved Row #(Not in table)
1001 Ted Madisson 9/7/2018 1
1001 Joyal Boston 10/4/2018 2
1001 Beatrice Chicago 1/1/2019 3
1001 System Chicago 1/5/2019 4
1001 John Austin 4/11/2019 5
1001 Simon Austin 6/11/2019 6
1001 Terry Cleveland 7/4/2019 7
1001 Hawkins Newyork 8/4/2019 8
1002 Devon Boston 12/4/2018 1
1002 Joy Austin 12/7/2018 2
1002 Rachael Newyork 12/19/2018 3
1002 Bill Chicago 1/4/2019 4
1002 System Dallas 2/12/2019 5
1002 Phil Austin 3/16/2019 6
1002 Dan Seattle 5/18/2019 7
1002 Claire Birmingham 7/7/2019 8
Tried sub query with row number function and not in ('Austin') filter
ROW_NUMBER() OVER(PARTITION BY Case ORDER BY Moved_date ASC) AS ROWNUM
Please note there are > 10k cases.
You can try this below script-
WITH CTE AS
(
SELECT [Case],[Name],Town,[Date Moved],
ROW_NUMBER() OVER (PARTITION BY [Case] ORDER BY [Date Moved]) [Row #]
FROM your_table
)
SELECT A.*
FROM CTE A
INNER JOIN
(
SELECT C.[Case],C.Town,MAX(C.[Row #]) MRN
FROM CTE C
INNER JOIN
(
SELECT *
FROM CTE A
WHERE A.Name = 'System'
)D ON C.[Case] = D.[Case] AND C.[Row #] > D.[Row #]
AND C.Town = 'Austin'
GROUP BY C.[Case],C.Town
)B ON A.[Case] = B.[Case] AND A.[Row #] = B.MRN+1
Output is -
Case Name Town Date Moved Row #
1001 Terry Cleveland 7/4/2019 6
1002 Dan Seattle 5/18/2019 7
Here are three possibilities. I'm still concerned about ties though. The first one will return multiple rows while the others only one per case:
with matches as (
select t1."case", min(t2."Date Moved") as "Date Moved"
from Movements r1 inner join Movements t2 on t1."case" = t2."case"
where t1.name = 'System' and t2.Town <> 'Austin'
and t2."Date Moved" > t1."Date Moved"
group by t1."case"
)
select t.*
from Movements t inner join matches m
on m."case" = t."case" and m."Date Moved" = t."Date Moved";
select m2.*
from Movements m1 cross apply (
select top 1 * from Movements m2
where m2.Town <> 'Austin' and m2."Date Moved" > m1."Date Moved"
order by m2."Date Moved"
) as match
where m1.name = 'System';
with m1 as (
select *,
count(case when name = 'System') over (partition by "case" order by "Date Moved") as flag
from Movements
), m2 as (
select *,
row_number() over (partition by "case" order by "Date Moved") as rn
from m1
where flag = 1 and name <> 'System' and Town <> 'Austin'
)
select * from m2 where rn = 1;
I'm basically assuming this is SQL Server. You might need a few minor tweaks if not.
It also does not require a town named Austin to fall between the "System" row and the desired row as I do not believe that was a stated requirement.

Case statement with a contains

This is a follow on from the below forum post:
Case statement with contains
I do apologise that I am writing a new post but I realised I missed out a lot of key information in my first forum post and if I added this on, this would confuse matters so thought I would just start over.
(I am using SSMS 2016)
I have got the below SQL code:
select
ContactGroupType.GroupID,FormattedName,GroupName,FormattedName,ContactGroupType.GroupType,[Address]
from ContactGroupContacts
left join ContactGroupType on ContactGroupContacts.GroupID = ContactGroupType.GroupID
left join ContactContacts on ContactGroupContacts.ContactID = ContactContacts.ContactID
left join ContactGroup_Details on ContactGroupType.GroupID = ContactGroupDetails.GroupID
left join Addresses on ContactGroupDetails.AddressID = Addresses.AddressID
left join ContactGroups on ContactGroupType.groupID = ContactGroups.groupID
where
ExpiryDate is null and
[Address] in ('9 fox ave','10 bush')
order by
FormattedAddress,
grouptype asc
With the above code, I am getting the below results:
Group_Ref | GroupName | Contact_Name | GroupType | Address
17766 MR D & N Goodwin Dan Goodwin Current Tenant 10 bush
17766 MR D & N Goodwin Nikki Goodwin Current Tenant 10 bush
17108 MRS A & P Bamer Amber Goodwin Current Tenant 9 fox ave
17108 MRS A & P Bamer Peter Goodwin Current Tenant 9 fox ave
2018 MR O & E Tofu Ola Tofu Former Tenant 9 fox ave
11875 MR D & N Biggs Dan Biggs Former Tenant 9 fox ave
12952 MR R & E Spur Richard Spur Former Tenant 9 fox ave
13193 MS N & E Snalles Nicole Snalles Former Tenant 9 fox ave
I need to write a case statement to show the following. So whenever an address has one or more current tenants ONLY, I need to show a '1'. If the address has one or more current AND former tenants, I need to show a '2'. please see below:
Group_Ref | GroupName | Contact_Name | GroupType | Address | Case
17766 MR D & N Goodwin Dan Goodwin Current Tenant 10 bush 1
17766 MR D & N Goodwin Nikki Goodwin Current Tenant 10 bush 1
17108 MRS A & P Bamer Amber Goodwin Current Tenant 9 fox ave 2
17108 MRS A & P Bamer Peter Goodwin Current Tenant 9 fox ave 2
2018 MR O & E Tofu Ola Tofu Former Tenant 9 fox ave 2
11875 MR D & N Biggs Dan Biggs Former Tenant 9 fox ave 2
12952 MR R & E Spur Richard Spur Former Tenant 9 fox ave 2
13193 MS N & E Snalles Nicole Snalles Former Tenant 9 fox ave 2
This works in SQL Server and it should work in both MySql and Oracle:
http://rextester.com/TID50546
CREATE TABLE TEST_TABLE (GroupType VARCHAR(20), Address VARCHAR(20));
INSERT INTO TEST_TABLE (GroupType, Address) VALUES ('Current Tenant', '10 bush');
INSERT INTO TEST_TABLE (GroupType, Address) VALUES ('Current Tenant', '10 bush');
INSERT INTO TEST_TABLE (GroupType, Address) VALUES ('Current Tenant', '9 fox');
INSERT INTO TEST_TABLE (GroupType, Address) VALUES ('Former Tenant', '9 fox');
SELECT A.GroupType
, A.Address
, CASE WHEN (SELECT COUNT(DISTINCT B.GroupType) FROM TEST_TABLE B WHERE B.Address = A.Address GROUP BY B.Address) = 1 THEN '1'
ELSE '2' END
FROM TEST_TABLE A
GROUP BY GroupType, Address;
SELECT
ContactGroupType.GroupID
, FormattedName
, GroupName
, FormattedName
, ContactGroupType.GroupType
, A.Address
, CASE WHEN (SELECT COUNT(DISTINCT CGT.GroupType)
FROM ContactGroupType CGT
LEFT JOIN ContactGroupDetails CGD
ON CGD.GroupID = CGT.GroupID
LEFT JOIN Addresses B
ON B.AddressID = CGD.AddressID
WHERE B.Address = A.Address
GROUP BY B.Address) = 1 THEN '1'
ELSE '2' END
FROM ContactGroupContacts
LEFT JOIN ContactGroupType
ON ContactGroupContacts.GroupID = ContactGroupType.GroupID
LEFT JOIN ContactContacts
ON ContactGroupContacts.ContactID = ContactContacts.ContactID
LEFT JOIN ContactGroup_Details
ON ContactGroupType.GroupID = ContactGroupDetails.GroupID
LEFT JOIN Addresses A
ON ContactGroupDetails.AddressID = A.AddressID
LEFT JOIN ContactGroups
ON ContactGroupType.groupID = ContactGroups.groupID
WHERE
ExpiryDate IS NULL AND
A.Address IN ('9 fox ave','10 bush')
ORDER BY
FormattedAddress
, grouptype asc

SQL - Return number times a value results from a query

I'm fairly new to SQL server (this is my second post on StackOverflow). I'm currently using SQL Server 2008 R2. I have a few tables that I've joined with the following query:
SELECT pt.first_name, pt.last_name, pt.provider_id,
pt.last_visit_date, pl.last_name
FROM dbo.pm_patient pt
INNER JOIN dbo.ProviderList pl
ON pt.provider_id = pl.provider_id
WHERE pt.last_visit_date >= '02/01/2012' AND pt.last_visit_date <= '02/01/2013'
ORDER BY provider_id
The result of the above query looks something like this:
first_name last_name provider_id last_visit_date last_name
Smith John 1 04/25/2012 Johnson
Doe Jane 1 02/25/2012 Johnson
Davies Ann 1 03/15/2012 Johnson
Dupree David 1 11/20/2012 Johnson
Jones Becky 1 04/21/2012 Smith
Diaz Mike 1 02/12/2012 Smith
Williams Allison 1 08/05/2012 Smith
Taylor Joe 1 10/01/2012 Smith
I would rather simply get the following result:
last_name NoOfPatients
Johnson 4
Smith 4
Could someone please help me?
Try :
SELECT pl.last_name, count(*) NoOfPatients
FROM dbo.pm_patient pt
INNER JOIN dbo.ProviderList pl
ON pt.provider_id = pl.provider_id
WHERE pt.last_visit_date >= '02/01/2012' AND pt.last_visit_date <= '02/01/2013'
GROUP BY pl.last_name
You need to read about how to use group in querys, basically what you need to do is count the number of patients and group by providers.
SELECT pt.last_name, COUNT(pt.*) NoOfPatients
FROM dbo.pm_patient pt
INNER JOIN dbo.ProviderList pl
ON pt.provider_id = pl.provider_id
WHERE pt.last_visit_date >= '02/01/2012' AND pt.last_visit_date <= '02/01/2013'
ORDER BY provider_id
GROUP BY pt.last_name