How to GROUP BY records with specific Columns only - sql-server

I have this query containing GROUP BY clause.
I only want to apply GROUP BY on FolioNumber only because the data in other columns is changing rapidly for same record due to UPDATE.
Here is the sample Query, I hope you don't need sample data and understand the query structure as this pretty simple.
SELECT MAX(TransactionNo) [TransactionNo], [FolioNo], [SalesOrderDate], [Center], [Company], [Customer],
[DeliveryAddress], [OfficialPhoneNo], [Item], [OrderQty], [UnitPrice], [Description], [FinishType],
[Remarks], [OrderNo], [BookNo], [CustomerAddress], [Customer], [DeliveryDate], [SalePerson]
[Status], [Discount], [NetAmount], [GrossAmount], [InvoiceDiscount], [GSTTax], [DateFrom], [DateTo]
FROM tblPageIndex
GROUP BY [FolioNo]

You need to use Over clause. find below sample query might will help you. As you have not provide any data set for unit test.
SELECT MAX(TransactionNo) over (partition by FolioNo) as [TransactionNo], [FolioNo], [SalesOrderDate], [Center], [Company], [Customer],
[DeliveryAddress], [OfficialPhoneNo], [Item], [OrderQty], [UnitPrice], [Description], [FinishType],
[Remarks], [OrderNo], [BookNo], [CustomerAddress], [Customer], [DeliveryDate], [SalePerson]
[Status], [Discount], [NetAmount], [GrossAmount], [InvoiceDiscount], [GSTTax], [DateFrom], [DateTo]
FROM tblPageIndex

I think you want data associated with each FoliyoNo where TransactionNo is maximum.
You can use ROW_NUMBER() to group the rows based on FoliyoNo and select the row with maximum value for TransactionNo
;WITH CTE AS (
SELECT [TransactionNo], [FolioNo], [SalesOrderDate], [Center], [Company], [Customer],
[DeliveryAddress], [OfficialPhoneNo], [Item], [OrderQty], [UnitPrice],
[Description], [FinishType], [Remarks], [OrderNo], [BookNo], [CustomerAddress],
[Customer], [DeliveryDate], [SalePerson]
[Status], [Discount], [NetAmount], [GrossAmount], [InvoiceDiscount],
[GSTTax], [DateFrom], [DateTo],
ROW_NUMBER() OVER(PARTITION BY [FolioNo] ORDER BY TransactionNo DESC) AS RN
FROM tblPageIndex
)
SELECT * FROM CTE WHERE RN = 1
From the comments, it turns out to know that you want all the rows with maximum TransactionNo in each FoliyoNo.
So you can change the ROW_NUMBER() to RANK() to achieve the desired result.

Related

Query to get oldest record

i have this following code:
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON) as [Time First Response]
from dbo.Email
where DirectionCode = '1'
)
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response]
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
order by dbo.Incident.new_CaseID desc
this query will return a result like :
As you can see, the query returning multiple records with same CASE ID. What i want is, for every multiple records have same CASE ID, only one with oldest [Time First Response] is retrieved
You can wrap your query in another CTE and use ROW_NUMBER to prioritize and get the oldest record per [CASE ID]:
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON)
as [Time First Response]
from dbo.Email
where DirectionCode = '1'
), cte2 as (
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response],
ROW_NUMBER() OVER (PARTITION BY dbo.Incident.new_CaseID
ORDER BY cte.[Time First Response]) AS rn
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
)
SELECT [CASE ID],
RegardingObjectId,
IncidentId,
[SUBJECT],
[STATUS],
[Time First Response]
FROM cte2
WHERE rn = 1
ORDER BY [CASE ID] desc
You can try using the MIN function
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON) as [Time First Response]
from dbo.Email
where DirectionCode = '1'
)
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response]
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
AND cte.[Time First Response] IN (SELECT MIN(cte.[Time First Response])
FROM cte WHERE cte.RegardingObjectId = dbo.Incident.IncidentId)
order by dbo.Incident.new_CaseID desc

Count and Row_Number

I want to get the top 5 Zipcodes for each Store with the highest Customers in them (zipcodes).
Please find below my query:
SELECT T.[Store], T.[ZipCode], Count(T.[Customer])
FROM ( SELECT T.[Store], T.[ZipCode],
Count(T.[Customer]) row_number() over (Partition By T.[StoreGitanjali] Order By Count (T.[Customer]) desc) as RN
FROM [Marketing].[dbo].[Poscus] as T
Group By T.[StoreGitanjali], T.[ZipCode]) as T
where T.RN <=5
Group By T.[StoreGitanjali], T.[ZipCode]
Please let me know how to use Count here in this scenario.
Thank you!
Example
CREATE TABLE #t
(
ID INT IDENTITY(1,1),
Customer NVARCHAR(3),
Store NVARCHAR(5),
ZIP INT
)
INSERT INTO #t VALUES('a', 'XYZ', 1234)
,('b', 'XYZ', 1234)
,('c', 'PQR', 1231)
,('d', 'PQR', 1231)
,('e', 'PQR', 1231)
,('f', 'XYZ', 1232)
,('g', 'XYZ', 1232)
,('h', 'XYZ', 1232)
,('i', 'PQR', 1236)
,('j', 'PQR', 1236)
,('k', 'LMN', 1237)
SELECT * FROM #t
The solution is, Set WHERE part < 2 according to your requirement.
SELECT TotalCustomer, Store, ZIP, Part FROM (
SELECT
COUNT(1) AS TotalCustomer,
Store,
ZIP,
ROW_NUMBER() OVER (PARTITION BY Store ORDER BY Store) AS Part
FROM #t
GROUP BY Store, ZIP
) t
WHERE Part < 2
ORDER BY Part
;WITH CTE
AS(
SELECT Store
,Zip
,COUNT(DISTINCT Customer) AS CustCount
FROM #t
GROUP BY Store,Zip
--ORDER BY Store,Zip
)
SELECT A.*
FROM(
SELECT *
--,DENSE_RANK() OVER(PARTITION BY Store ORDER BY CustCount DESC) AS DenRank
,ROW_NUMBER() OVER(PARTITION BY Store ORDER BY CustCount DESC) AS DenRank
FROM CTE
--ORDER BY Store,Zip
) AS A
WHERE A.DenRank <= 2

T-SQL return top one field based on count of another

I've struggled to search successfully for this as I haven't figured out a search string describing what I want to do, apologies if this has been covered already.
I have a table that contains among others a contract number, a start date, a serial number and a datestamp. These are Many:Many.
What I'm trying to achieve is to return the start date for each individual contract number with the largest number of unique serial numbers and the most recent datestamp, where that start date is valid.
This, as I guess is obvious to T-SQL experts only returns me the one contract number with the largest number of serials. Can anyone tell me what I'm doing wrong?
SELECT TOP (1)
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract ID], [Item Begin Date], Datestamp
HAVING
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
ORDER BY
CountSerials DESC, Datestamp DESC
Cheers,
Alex
You can put that into a temporary table (without using TOP (1) or oder by):
I changed some table names in the process,
if exists (select * from tempdb.sys.tables where name = '##tmp')
drop table ##tmp
SELECT * into ##tmp
from
(
select
[Contract_ID], [Begin_Date] AS Start_Date,
COUNT([serials]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract_ID], [begin_date], Datestamp
HAVING
[begin_date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102)
) a
select contract_id,Start_Date, max(countserials) as MAXCOUNT, Datestamp from ##tmp
group by contract_id,Start_Date,Datestamp
you can do a subquery with aggregation and extract your desired results from it:
SELECT distinct *
FROM
(
Select
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) OVER(PARTITION BY [Contract ID]) AS CountSerials,
datestamp,
MAX(Datestamp) OVER (PARTITION BY [Contract ID]) maxdatestamp
FROM
SourceTable
WHERE
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
) x
WHERE
datestamp=maxdatestamp

TSQL - Unpivot multiple columns

How can I unpivot multiple columns in "one"?
Right now I have an unpivot for each column but this creates a lot of empty rows.
See the screenshot please.
At the top you see the input data. At the moment I'm at the table in the middle with this code:
SELECT [ID], [RowNumber], [Year], [Sales] FROM (
SELECT ID, RowNumber, [Sales 2013] as [2013], [Sales 2014] as [2014]
FROM mytable) p UNPIVOT (
[Sales] FOR [Year] IN ([2013], [2014]) )AS unpvt ;
But I think it would be much better to get to the bottom table structure since the actual data contains more columns and more years to deal with.
Here's a Fiddle with the sample data.
Hope you can show me a way to get there.
Thank you.
SELECT [ID],
[RowNumber],
[Year],
Sales,
Budget
FROM mytable
CROSS APPLY (VALUES (2013, [Sales 2013], [Budget 2013]),
(2014, [Sales 2014], [Budget 2014]) )
V([Year], Sales, Budget)
SQL Fiddle
One approach is to repivot after unpivoting - like so:
select [Id], [Year], [Sales], [Budget], [Actual] from
(SELECT [Id],
Left([Colhead], charindex(' ',[Colhead])-1) [Category],
Right([Colhead], len([Colhead])-charindex(' ',[Colhead])) [Year],
[Figures]
FROM (SELECT * FROM mytable) p
UNPIVOT ([Figures] FOR [Colhead] IN
([Sales 2013],[Sales 2014],[Budget 2013],[Budget 2014],[Actual 2013],[Actual 2014])
)
AS unpvt) as u
pivot
(max([Figures]) for [Category] in ([Sales], [Budget], [Actual])) as p
SQLFiddle here.

How do I form a query with a running count retaining the order

I have a trace table which looks like this
I'd like to get a running total which looks like the following output - its very important that I retain the order - as this is the execution order of the stored porcedures - It will help me analyze bottle necks in the system
I have tried
select max(RowNumber),objectname, count(1) from rob
where eventclass = 42
group by objectname
But that mucks up the order
Is this even possible in SQL?
UPDATE:
I tried this
select RowNumber,objectname, count(1) from rob
where eventclass = 42
group by objectname,RowNumber
order by RowNumber
But this (as the query quite rightly says groups by rownumber (have to have that to have it in the order by) )
select objectname,
count(*)
from (
select RowNumber,
objectname,
row_number() over(order by RowNumber) - row_number() over(order by objectname, RowNumber) as grp
from rob
where eventclass = 42
) as T
group by grp, objectname
order by min(RowNumber)
Working sample using a table variable.
declare #T table
(
RowNumber int,
objectname varchar(50)
)
insert into #T values
(8, 'f_system_log_init'),
(10, 'f_purge_system_log'),
(25, 'f_system_log_msg'),
(65, 'f_system_log_msg'),
(104, 'f_system_log_msg'),
(143, 'f_system_log_msg'),
(182, 'f_system_log_msg'),
(221, 'f_system_log_msg'),
(5015, 'f_get_system_logs_parent_log_id_for_dataloader'),
(5055, 'f_system_log_msg'),
(5096, 'f_system_log_msg')
select objectname,
count(*)
from (
select RowNumber,
objectname,
row_number() over(order by RowNumber) - row_number() over(order by objectname, RowNumber) as grp
from #T
) as T
group by grp, objectname
order by min(RowNumber)
Result:
objectname
-------------------------------------------------- -----------
f_system_log_init 1
f_purge_system_log 1
f_system_log_msg 6
f_get_system_logs_parent_log_id_for_dataloader 1
f_system_log_msg 2
Try this:
;WITH CTE as (select *,ROW_NUMBER() over(order by rownumber,objectname) rn from test101)
,CTE1 as(
select *,1 as incr from CTE where rn=1
union all
select t.*,
CASE WHEN t.objectname=c.objectname then incr else incr+1 end as incr
from CTE t inner join CTE1 c
on t.rn=c.rn+1
)
select max(objectname),count(incr) from CTE1
group by incr

Resources