SQL Query: New columns for data with some matching criteria - sql

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

Related

How do I conditionally select a unique value in SQL?

I've been tasked with returning only rows with unique IDs but returning a row for every ID in SQL. How would I go about this?
Logic:
For primary row, select where JOB_INDICATOR = ā€˜Pā€™. If there are multiple rows, then use the record where PRIM_ROLE_IND = ā€˜Yā€™. If there are still multiple then select the lowest numbered EMPL_RCD starting at 0.
Example starting point:
id
name
job
job_indicator
prim_role_ind
empl_rcd
1001
John Doe
Director
P
N
0
1001
John Doe
Professor
P
Y
1
1001
John Doe
Coach
N
N
2
1002
Bob Jones
Head Janitor
P
Y
0
1002
Bob Jones
Associate Janitor
P
Y
1
1003
Susan Smith
Groundskeeper
P
N
0
1003
Susan Smith
Professor
P
N
1
Desired return:
id
name
job
job_indicator
prim_role_ind
empl_rcd
1001
John Doe
Professor
P
Y
1
1002
Bob Jones
Head Janitor
P
Y
0
1003
Susan Smith
Groundskeeper
P
N
0
So far, I have the below, but a new requirement was added to do conditional components.
SELECT *
FROM EMPLOYEE
WHERE JOB_INDICATOR = 'P'
You can use window function ROW_NUMBER() to accomplish this:
SELECT *
FROM
(
SELECT EMPLOYEE.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY
prim_role_ind DESC, empl_rcd ASC) as rn
FROM EMPLOYEE
WHERE JOB_INDICATOR = 'P'
) dt
WHERE rn = 1

Display Value From Another Row

I have to write a query to display the value for ID2 when ID=ID. Currently the table looks like the below.
ID
ID2
fname
lname
address1
address2
city
state
123
123
joe
smith
12 main st
los angeles
CA
122
122
james
jones
13 main st
new york
NY
123
3210
joe
smith
14 main st
los angeles
CA
124
124
mary
jones
15 main st
new york
NY
The desired output would look like this. Where I can do some sort of a self join to get the ID2 value.
ID
ID2
fname
lname
address1
address2
city
state
other ID
123
123
joe
smith
12 main st
los angeles
CA
3210
122
122
james
jones
13 main st
new york
NY
124
124
mary
jones
15 main st
new york
NY
Any ideas/suggestions greatly appreciated!
Update:
I was able to get the result with the additional columns using the below script. Thanks all for your assistance on this one!
with cte (id, id2, fname, lname, address1, address2, city, state)
as (select *
from (select *,row_number() over(partition by id order by id desc) as rn from your_table
) x
where rn = 2)
select x.id, x.id2, x.fname, x.lname, x.address1, x.address2, x.city, x.state, c.id2, c.address1
from (select *,row_number() over(partition by id order by id desc) as rn from your_table
) x
left join
cte c on x.id=c.id
where x.rn = 1
dbfiddle below
https://dbfiddle.uk/?rdbms=postgres_9.5&fiddle=4010ab08c5e32d9293d10e985adbfd7a
You could do something like the following, using a correlated subquery; using max ensures it only returns a single row should you have an Id with more than one different ID2:
select *,
(select max(id2) from t t2 where t2.id = t.id and t2.id2 != t.id) OtherId
from t
where id = id2
If you have two rows max with the same id, then you can try this :
SELECT (array_agg(t.*) FILTER (WHERE id = id2))[1].*
, (array_agg(t.id2) FILTER (WHERE id <> id2))[1] AS "other ID"
FROM your_table AS t
GROUP BY id
If you may have more than two rows with the same id then you can try this :
SELECT (array_agg(t.*) FILTER (WHERE id = id2))[1].*
, array_agg(t.id2) FILTER (WHERE id <> id2) AS "other IDs"
FROM your_table AS t
GROUP BY id
see the test result in dbfiddle

Find intersecting dates

Can somebody help me with next problem. I have MS Access table, lets say with my employees, and for each one of them I have start and end date of their vacation:
Name begin end
John 1.3.2021. 15.3.2021.
Robert 6.3.2021. 8.3.2021.
Lisa 13.3.2021. 16.3.2021.
John 1.4.2021. 3.4.2021.
Robert 2.4.2021. 2.4.2021.
Lisa 15.5.2021. 23.5.2021.
Lisa 5.6.2021. 15.6.2021.
How to get the result with number of employees which are absent from work per each date from the table (dates which are included into intervals begin-end). For example:
1.3.2021. 1 '>>>only John
2.3.2021. 1 '>>>only John
3.3.2021. 1 '>>>only John
4.3.2021. 1 '>>>only John
5.3.2021. 1 '>>>only John
6.3.2021. 2 '>>>John and Robert
7.3.2021. 2 '>>>John and Robert
...
Thank you in advanced!
You can use union to combine the tables and a correlated subquery:
select dte,
(select count(*)
from t
where d.dte between t.[begin] and t.[end]
) as cnt
from (select [begin] as dte
from t
union
select [end]
from t
) d;

How to query: "for which do these values apply"?

I'm trying to match and align data, or resaid, count occurrences and then list for which values those occurrences occur.
Or, in a question: "How many times does each ID value occur, and for what names?"
For example, with this input
Name ID
-------------
jim 123
jim 234
jim 345
john 123
john 345
jane 234
jane 345
jan 45678
I want the output to be:
count ID name name name
------------------------------------
3 345 jim john jane
2 123 jim john
2 234 jim jane
1 45678 jan
Or similarly, the input could be (noticing that the ID values are not aligned),
jim john jane jan
----------------------------
123 345 234 45678
234 123 345
345
but that seems to complicate things.
As close as I am to the desired results is in SQL, as
for ID, count(ID)
from table
group by (ID)
order by count desc
which outputs
ID count
------------
345 3
123 2
234 2
45678 1
I'll appreciate help.
You seem to want a pivot. In SQL, you have to specify the number of columns in advance (unless you construct the query as a string).
But the idea is:
select ID, count(*) as cnt,
max(case when seqnum = 1 then name end) as name_1,
max(case when seqnum = 2 then name end) as name_2,
max(case when seqnum = 3 then name end) as name_3
from (select t.*,
row_number() over (partition by id order by id) as seqnum -- arbitrary ordering
from table t
) t
group by ID
order by count desc;
If you have an unknown number of columns, you can aggregate the values into an array:
select ID, count(*) as cnt,
array_agg(name order by name) as names
from table t
group by ID
order by count desc
the query would look similar to this if that's what you're looking for.
SELECT
name,
id,
COUNT(id) as count
FROM
dataSet
WHERE
dataSet.name = 'input'
AND dataSet.id = 'input'
GROUP BY
name,
id

Select records with fewer than 10 entries sql server

i want only to display the The ID which have record less than 10 entries for each ID, an ID may have several values as you see in the data below. i want
i have tried this query but it selects also the record for ID 2
select ID, Name ,LastName ,PaymentDate,POSITION
From ( select ID, Name ,LastName ,PaymentDate ,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY PaymentDate DESC) AS POSITION
)
where Position < 10
any help please
ID Name LastName PaymentDate
1 John Abraham 2015-05-08
1 John Abraham 2014-05-08
1 John Abraham 2013-05-08
1 John Abraham 2012-05-08
1 John Abraham 2011-05-08
1 John Abraham 2010-05-08
------------------------------
2 Adam White 2015-05-08
2 Adam White 2014-05-08
2 Adam White 2013-05-08
2 Adam White 2012-05-08
2 Adam White 2011-05-08
2 Adam White 2010-05-08
2 Adam White 2009-05-08
2 Adam White 2008-05-08
2 Adam White 2007-05-08
2 Adam White 2006-05-08
2 Adam White 2005-05-08
2 Adam White 20004-05-08
SELECT ID, COUNT(ID)
FROM sometable
GROUP BY ID
HAVING COUNT(ID) < 10
You want count(*), not row_number():
select ID, Name, LastName, PaymentDate
from (select ID, Name, LastName, PaymentDate,
count(*) over (partition by ID) as cnt
from . . .
) t
where cnt < 10;
This displays the rows (which your question suggests is what you want). If you want only the ids, then aggregation is better:
select id
from t
group by id
having count(*) < 10;
Please try:
Select ID, Name, LastName, PaymentDate
From MyTable
Where ID in (Select ID From MyTable Group By ID Having Count(*) < 10);