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

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

Related

Select records based on Id and most updated record of the same Id

I have a table Applications
The user can submit more than one application. The user can also update an existing application, but instead of updating the record itself, we will insert a new record with the same ApplicationNumber
Id ApplicationNum ApplicantId ApplicantName CreateDate
1 101 789 John May-20-2021
2 101 789 John May-21-2021
3 102 789 John May-22-2021
4 103 123 Maria May-31-2021
I want to return the list of applications based on the ApplicantId, but I don’t want to display both records of the same ApplicationNumber
If I use this select statement
Select * from Applications where ApplicantId = 789
This is the result I currently get
1 101 789 John May-20-2021
2 101 789 John May-21-2021
3 102 789 John May-22-2021
This is the result I want to get
2 101 789 John May-21-2021
3 102 789 John May-22-2021
Notice that record Id = 1 is not displayed because it is an old version of record Id = 2
How can I achieve this?
I like using ROW_NUMBER along with a TIES trick here:
SELECT TOP 1 WITH TIES *
FROM Applications
WHERE ApplicantId = 789
ORDER BY ROW_NUMBER() OVER (PARTITION BY ApplicantId, ApplicationNum ORDER BY Id DESC);
Might be easier to just use:
select max(Id) as Id, ApplicationNum, ApplicantId, ApplicantName, max(CreateDate) as CreateDate
from Applications
where ApplicantId = 789
group by ApplicationNum, ApplicantId, ApplicantName
The traditional way which is usually the most performant is to use row_number and select the desired row from each group of Applicants
select Id, ApplicationNum, ApplicantId, ApplicantName, CreateDate
from (
select *, Row_Number() over(partition by ApplicantId, ApplicationNum order by Id desc) rn
from Applications
where ApplicantId=789
)a
where rn=1

Separate distinct values in to columns

Hi all I am quite new to SQL. I have a table (TABLE1) with two columns as below
Name age
--------
jim 18
jim 21
dave 18
dave 18
john 23
john 41
I need to create a view in SSMS which lists distinct ages for each name in a separate column as below
Jim Dave John
---------------
18 18 23
21 41
I have tried a sub query like
SELECT DISTINCT AGE FROM TABLE1 WHERE NAME = JIM
But I encountered a sub query cannot return more than one value.
You can use row_number() & do aggregation :
select max(case when name = 'jim' then age end) as jim,
max(case when name = 'dave' then age end) as dave,
max(case when name = 'john' then age end) as john
from (select t.*, row_number() over (partition by name order by age) as seq
from table t
) t
group by seq;

How to select only details of min value only in SQL?

I could get the minimum percentage of two values, but I need only the name, and ID in the select.
ID NAME CITY ONE TWO
--------------------------------------------------
2 Morales Los Angeles 40 10
1 John New York 60 20
4 Mary San Diego 10 10
I need to get the min value of one/two, and to only appear this as a result:
ID NAME
---------
4 Mary
Select ID, NAME
from MYTABLE
where least(ONE,TWO) = (select min(least(ONE,TWO)) from MYTABLE);
If you don't want Morales, then you can do this :
Select ID, NAME
from MYTABLE
where id =
(select id from
(select id from MYTABLE order by least(ONE,TWO), ONE*TWO)
where rownum <= 1);

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);

using dense_rank to find distinct

I have a table something like this
Id student_name City
4 abc Mumbai
6 xyz Delhi
4 lmn Kolkata
6 abc Mumbai
6 GHI Chennai
I am using dense_rank() function to dismiss the duplicate entry of ID in the table means if I am having the ID 4 twice it should give me only once in the output.
When I am using dense_rank function like:
select dense_rank() over (order by student_id desc ) as ID ,Id, student_name,city
from test
It is giving me the output something like this
ID ID student_name city
1 4 abc Mumbai
1 4 lmn kolkata
2 6 xyz Delhi
2 6 abc Mumbai
But I don't want duplicate how to remove using dense_rank() function
First, dense_rank() in the select does not do filtering. So, I don't know why the output would have four rows when the input has five.
Second, to keep only one row per id, then use row_number(), not dense_rank() . . . along with a subquery:
select t.*
from (select t.*,
row_number() over (partition by student_id order by student_id) as seqnum
from test t
) t
where seqnum = 1;