SQL Server query distinct - sql

I'm trying to do a query in SQL Server 2008. This is the structure of my table
Recno ClientNo ServiceNo
---------------------------------
1234 17 27
2345 19 34
3456 20 33
4567 17 34
I'm trying to select RecNo however, filtering by distinct ClientNo, so for some clients such as client no 17 - they have more than 1 entry, I'm trying to count that client only once. So basically, looking at this table, I'm only supposed to see 3 RecNo's, since there are only 3 distinct clients. Please help
Select RecNo, Count(ClientNo)
from TblA
where Count(clientNo)<2
Something like this?
EDIT:
The value of RecNo is not relevant, I only need to have an accurate number of records. In this case, I'd like to have 3 records.

oaky you are getting some crazy answers probably becuase your desired result is not clear so I suggest if some of these are not what you need that you clarify your desired result.
If you want the answer 3, I can only assume you want a count of DISTINCT ClientNo's if so it is simply aggregation.
SELECT COUNT(DISTINCT ClientNo) as ClientNoDistinctCount
FROM
TblA
GROUP BY
ClientNo

Ok, this will give you the count that you want:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY ClientNo ORDER BY Recno)
FROM TblA
)
SELECT COUNT(DISTINCT Recno) N
FROM CTE
WHERE RN = 1;

Try this..
;with cte1
As(SELECT Recno,clientno
,row_number() over(partition by clientno order by Recno )RNO FROM TblA)
Select Recno,clientno
From cre1 where RNO=1

Choose only ClientNo having the max Recno (or replace < with > to choose the min one).
Select *
from TblA t1
where not exists(select 1
from TblA t2
where t1.ClientNo = t2.ClientNo and t1.Recno < t2.Recno )
BTW, the other solution already mentioned, utilizing row_number() needs no CTE in this case
SELECT TOP(1) WITH TIES *
FROM TblA
ORDER BY ROW_NUMBER() OVER(PARTITION BY ClientNo ORDER BY Recno)

Related

How to group and pick only certain values based on a field using select query SQL

I have a table as follow
ID
ORDERNO
1
123
1
123
2
456
2
456
During every select query done via application using JDBC, only the grouped records based on ORDERNO should be picked.
That means, for example, during first select query only details related to ID = 1, but we cannot specify the ID number in where clause because we do not know how many number of IDs will be there in future. So the query should yield only one set of records; application will delete those records after picking, hence next select query will result in picking other set of records. How to achieve it?
You can use TOP WITH TIES for this
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID;
If you want to select and delete at the same time you could delete using an OUTPUT clause
WITH cte AS (
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID
)
DELETE cte
OUTPUT deleted.*;
As one option you could select on the MIN(ID) like:
SELECT *
FROM yourtable
WHERE ID = (SELECT MIN(ID) FROM yourtable);
You could also use window functions to do this:
SELECT ID, ORDERNO
FROM
(
SELECT ID, ORDERNO
DENSE_RANK() OVER (ORDER BY ID ASC) AS dr
FROM yourtable
)dt
WHERE dr = 1;
order your rows and select top n number of rows that you want :
select top (1) with ties ID, ORDERNO
from tablename
order by ID asc

Grouping values by a column and getting min value of another with another column

My table structure is as follows
userId period pcount
a 01/03 100
a 02/03 150
a 03/03 200
b 02/03 250
...and so on..
I wish to get the row which has the minimum pcount for each userid, so the result for userid a ought to be as below..
a 01/03 100
If I did not want the period value, I could have grouped the table by userId and selected userId and MIN of pcount.
But, since I need the period as well, what should I do..
Though I'm using SQL Server on azure,it might change and so would appreciate standard ansi sql query.
Thanks
In general these kind of requests are handled through ROW_NUMBER
Select * From
(
select row_number() Over(Partition by userId Order by pcount asc) as rn,*
From yourtable
) A
Where Rn = 1
Another approach using INNER JOIN works with most of the DBMS
SELECT A.*
FROM yourtable A
INNER JOIN (SELECT userId,
Min(pcount) AS M_pcount
FROM yourtable
GROUP BY userId) B
ON A.userId = B.userId
AND A.pcount = B.M_pcount

Alternative to using ROW_NUMBER for better performance

I have a small query below where it outputs a row number under the RowNumber column based on partitioning the 'LegKey' column and ordering by UpdateID desc. This is so the latest updated row (UpdateID) per legkey is always number 1
SELECT *
, ROW_NUMBER() OVER(PARTITION BY LegKey ORDER BY UpdateID DESC) AS RowNumber
FROM Data.Crew
Data outputted:
UpdateID LegKey OriginalSourceTableID UpdateReceived RowNumber
7359 6641 11 2016-08-22 16:35:27.487 1
7121 6641 11 2016-08-15 00:00:47.220 2
8175 6642 11 2016-08-22 16:35:27.487 1
7122 6642 11 2016-08-15 00:00:47.220 2
8613 6643 11 2016-08-22 16:35:27.487 1
7123 6643 11 2016-08-15 00:00:47.220 2
The problem I have with this method is that I am getting slow performance because I assume I am using the ORDER BY.
My question is that is there an alternative way to produce a similar result but have my query run faster? I am thinking a MAX() may work but I didn't get the same output as before. Maybe I did the MAX() statement incorrectly so was wondering if this is a good alternative if somebody can provide an example on how they would write the MAX() statement for this example?
Thank you
Presumably this is the query you want to optimize:
SELECT c.*
FROM (SELECT c.*,
ROW_NUMBER() OVER (PARTITION BY LegKey ORDER BY UpdateID DESC) AS RowNumber
FROM Data.Crew c
) c
WHERE RowNumber = 1;
Try an index on Crew(LegKey, UpdateId).
This index will also be used if you do:
SELECT c.*
FROM Data.Crew c
WHERE c.UpdateId = (SELECT MAX(c2.UpdateId)
FROM Data.Crew c2
WHERE c2.LegKey = c.LegKey
);
You can try one of the following:
declare #Table table(UpdateID int, LegKey int, OriginalSourceTableID int, UpdateReceived datetime)
Here using the MAX Date in subquery.
select * from #Table as a where a.UpdateReceived = (Select MAX(UpdateReceived) from #Table as b Where b.LegKey = a.LegKey)
Here you can use it in cte with group by.
with MaxDate as( Select LegKey, Max(UpdateReceived) as MaxDate from #Table group by LegKey )
select * from MaxDate as a
inner join #Table as b
on b.LegKey=a.LegKey
and b.UpdateReceived=a.MaxDate

Getting all fields from table filtered by MAX(Column1)

I have table with some data, for example
ID Specified TIN Value
----------------------
1 0 tin1 45
2 1 tin1 34
3 0 tin2 23
4 3 tin2 47
5 3 tin2 12
I need to get rows with all fields by MAX(Specified) column. And if I have few row with MAX column (in example ID 4 and 5) i must take last one (with ID 5)
finally the result must be
ID Specified TIN Value
-----------------------
2 1 tin1 34
5 3 tin2 12
This will give the desired result with using window function:
;with cte as(select *, row_number(partition by tin order by specified desc, id desc) as rn
from tablename)
select * from cte where rn = 1
Edit: Updated query after question edit.
Here is the fiddle
http://sqlfiddle.com/#!9/20e1b/1/0
SELECT * FROM TBL WHERE ID IN (
SELECT max(id) FROM
TBL WHERE SPECIFIED IN
(SELECT MAX(SPECIFIED) FROM TBL
GROUP BY TIN)
group by specified)
I am sure we can simplify it further, but this will work.
select * from tbl where id =(
SELECT MAX(ID) FROM
tbl where specified =(SELECT MAX(SPECIFIED) FROM tbl))
One method is to use window functions, row_number():
select t.*
from (select t.*, row_number() over (partition by tim
order by specified desc, id desc
) as seqnum
from t
) t
where seqnum = 1;
However, if you have an index on tin, specified id and on id, the most efficient method is:
select t.*
from t
where t.id = (select top 1 t2.id
from t t2
where t2.tin = t.tin
order by t2.specified desc, id desc
);
The reason this is better is that the index will be used for the subquery. Then the index will be used for the outer query as well. This is highly efficient. Although the index will be used for the window functions; the resulting execution plan probably requires scanning the entire table.

SQL compare two max Dates from the same table

I dont know how to call this topic so I thought I just would explain what I need.
I have the following table:
Id IdPerson date successfully
1 1 01.01.2012 FALSE
2 1 01.01.2014 TRUE
3 2 01.01.2014 FALSE
Now I want all IdPerson where the newest entry is FALSE
So that would be just IdPerson 2 because IdPerson 1 is true in 2014.
I really have no clue how to do that.
Can somebody help me?
Greets
There is an interesting approach to this that uses conditional aggregation:
select idperson
from table t
group by idperson
having max(date) = max(case when successfully = 'false' then date end);
Note: this solution (as well as the others) assume that date is stored in a native date/time format. If not, you should fix the database, but this query would need to use convert().
If you are using SQL Server 2008 R2 (or higher), then you can use Apply
select p.* from Person P
cross Apply
(
select MAX(date) [maxdate] from Person group by Id
)a
where P.Date = a.maxdate and p.Successfully = 0
Use ROW_NUMBER() OVER (PARTITION BY ...) in a subquery to locate the newest entry per person. Then, in the outer query, select only those having successfully = 'FALSE':
SELECT Id, IdPerson, [date]
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY IdPerson ORDER BY [date] DESC) AS rn,
*
FROM MyTable ) t
WHERE t.rn = 1 AND t.successfully = 'FALSE'
I tried this in mysql:
SELECT Id,IdPerson,date,Status from MyTable
WHERE status='false' AND date= ALL( SELECT max(date) from MyTable
GROUP BY IdPerson);