Applying window function in one query without CTE - sql-server

I have been searched in the net and trying to create a query that contains a window function without a CTE but I couldn't get the result and I need some help
this my query that I create with a CTE what I need is doing that in one query
;with cte(Gid, id, prod, orderdate, shipdate, ranking) as
(
select
p1.Gid Gid,
p1.id id,
p1.prod prod,
p1.orderdate orderdate,
p2.shipdate shipdate,
rank() over (partition by p1.prod order by p1.id desc) ranking
from
shpro p1
inner join
shpro p2 on p1.id = p2.id
where
cast(p1.orderdate as DATE) > GETDATE()
and cast(p1.shipdate as DATE) < GETDATE() - 1
)
select *
from cte
where ranking = 1

Demo with some test data on how this works
select top (1) with ties
p1.Gid Gid,
p1.id id,
p1.prod prod,
p1.orderdate orderdate,
p2.shipdate shipdate
from shpro p1 inner join shpro p2
on p1.id=p2.id
where cast(p1.orderdate as DATE)>GETDATE() and cast(p1.shipdate as DATE)<GETDATE()-1
order by
Rank() over (partition by p1.prod order by p1.id desc)
This works like below..
1.order by arranges all the rows based on their rank
2.Top 1 with ties options fetches all the rows which are tied
References:
T-SQL Querying (Developer Reference)
Below is some sample data to play with:
CREATE TABLE #TEST
(
Id INT,
Name VARCHAR(10)
)
Insert Into #Test
select 1,'A'
Union All
Select 1,'B'
union all
Select 1,'C'
union all
Select 2,'D'
select top 1 with ties id,name
from #test
order by row_number() over (partition by id order by id)

CTE can be translated directly into subquery. Yours query should look similar to following:
SELECT * FROM
(
select
p1.Gid Gid,
p1.id id,
p1.prod prod,
p1.orderdate orderdate,
p2.shipdate shipdate,
rank() over (partition by p1.prod order by p1.id desc) ranking
from
shpro p1
inner join
shpro p2 on p1.id = p2.id
where
cast(p1.orderdate as DATE) > GETDATE()
and cast(p1.shipdate as DATE) < GETDATE() - 1
) CteAsSubquery
WHERE ranking = 1
Note alias CteAsSubquery is there (most common error).

Related

Most Recent Data

I have a schema that looks like this.
Using the recordings table , query the most recent data in the database for each entityid/accid/month combination (Main Table is the main table)
use row_number()
select * from
(
select *,row_number() over(partition by entid, accid, month order by timestamp desc) as rn
from recordings a inner join maintable b on a.logid=b.logid
)A where rn=1
use row_number()
select * from
(
select m.*, row_number() over(partition by acctid,entid,month order by timestamp desc) rn
from maintable m join racordings r on m.logid=r.logid
) a where a.rn=1
Here's your query.
select * from
(select m.*, r.*, e.*, a.*, row_number() over(partition by a.AcctID, e.EntID, Month order by r.TimeStamp desc) row_num
from maintable m
inner join racordings r on m.LogID = r.LogID
inner join Entities e on e.EntID = m.EntID
inner join AccInfo a on a.AcctID = m.AcctID
) t1
where t1.row_num = 1

How to get desired result by combining two CTE's with different tables?

I have two CTE's,firstly
;WITH CTE AS (SELECT A.*
, Row_NUMBER() Over (Partition by ID order by Date asc) RN
FROM TABLE A)
SELECT Sum(Weight) as IN_WT
FROM CTE
WHERE RN = 1 and name='dev1'
and then
;WITH CTE AS (SELECT B.*
, Row_NUMBER() Over (Partition by ID order by Date desc) RN1
FROM TABLE B)
SELECT Sum(Weight) AS out_wt
FROM CTE
WHERE RN1 = 1 and name='dev1'
Here we had two tablesTableA,TableB.We are getting In_wt from TableA and Out_wt from TableB.Now I had a requiremnt that the output should be combined and get in_wt,out_wt in single row from different tables and same name.I tried combining both the CTE's but didn't get the desired result.How can we do that?
Try this:
;WITH CTE1 AS (
SELECT name,
Row_NUMBER() Over (Partition by ID order by Date asc) RN
FROM TABLEA
), CTE2 AS (
SELECT name,
Row_NUMBER() Over (Partition by ID order by Date desc) RN
FROM TABLEB
)
SELECT (SELECT Sum(Weight) FROM CTE1 WHERE RN = 1 and name='dev1') AS IN_WT,
(SELECT Sum(Weight) FROM CTE2 WHERE RN = 1 and name='dev1') AS OUT_WT

How to list duplicate records?

I have the following table structure:
id|date|studenttypeid|name|audituser
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
4|.....|4|Dan|....
5|.....|4|Robin|....
I need to list all records which are duplicates on studenttypeid + name.
With the above data, the query should give me the following output:
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
5|.....|4|Robin|....
How can I achieve this on SQL Server 2008?
You can use a group by and then join back to the original table, like this:
WITH Temp(StudentTypeId, Name) AS(
SELECT
StudentTypeId, Name
FROM YourTable
GROUP BY
StudentTypeId, Name
HAVING Count(1) > 1
)
SELECT YourTable.*
FROM YourTable
INNER JOIN Temp
ON YourTable.StudentTypeId = Temp.StudentTypeId
AND YourTable.Name = Temp.Name
you can use ROW_NUMBER()
SELECT ID, DATE, studenttypeid, name, audituser
FROM
(
SELECT ID, DATE, studenttypeid, name, audituser,
ROW_NUMBER() OVER (PARTITION BY studenttypeid, name
ORDER BY id) rn
FROM yourTableName
) a
WHERE rn = 1
SQLFiddle Demo
If you want to include every occurrence of the duplicates, some more methods using CROSS APPLY...
SELECT p.*
FROM people p
CROSS APPLY (
SELECT TOP(1) * FROM people p2 WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
) as pWithDups
Or an EXISTS check
SELECT p.*
FROM people p
WHERE EXISTS (
SELECT *
FROM people p2
WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
)
Try this
SELECT a.*
FROM yourtable a
JOIN (SELECT studenttypeid,
name
FROM yourtable
GROUP BY studenttypeid,
name
HAVING Count(studenttypeid) > 1) b ON b.name = a.name
ORDER BY a.id

How to get rows with Maximum id with condition of a table in SQL Server

i have a table similar this
id-value-RowInid
1-xy-1
1-xx-2
1-xz-3
2-xx-1
2-xr-2
3-xq-1
4-xa-1
4-xc-2
...
i need a function for this table with similar output to get maximum of RowInid in separated id group
1-xz-3
2-xr-2
3-xq-1
4-xc-2
...
You just need to use MAX(RowInid) with GROUP BY Id, value
SELECT ID, VALUE, MAX(RowInid) FROM myTable GROUP BY ID, VALUE
EDIT:
As you updated your question, you can get value field using sub-query like this:
SELECT ID, VALUE, RowInid
FROM myTable t1 WHERE RowInid =
(
SELECT MAX(RowInid) FROM myTable WHERE id = t1.id GROUP BY id
)
ORDER BY id ASC;
You can also achieve this using INNER JOIN like this:
SELECT t2.ID, VALUE, t2.RowInid FROM myTable t1
INNER JOIN
(
SELECT ID, MAX(RowInid) AS RowIniD FROM myTable GROUP BY ID
) AS t2
ON t1.ID = t2.ID AND t1.RowInid = t2.RowInid
ORDER BY t1.ID ASC;
See this SQLFiddle
See more about GROUP BY and MAX in SQL Server.
no need for group by or max at all
select id, value, rowinid from
( select *, row_number() over (partition by id, order by rowinid desc) rn from yourtable ) v
where rn = 1
Try with,
Use Sub Query to get Id, Value and Max RowInid,
SELECT m1.[Id],m1.Value, m1.RowInid
FROM [Practice].[dbo].[myTable] m1 WHERE RowInid = (SELECT MAX(m2.RowInid) FROM [Practice].[dbo].[myTable] m2 WHERE M1.Id = m2.Id GROUP BY Id)
above query return result like:
4-xx-2
3-xx-1
2-xx-2
1-xx-3
To Ascending this use,
SELECT m1.[id],m1.Value, m1.RowInid
FROM [Practice].[dbo].[myTable] m1 WHERE m1.RowInid = (SELECT MAX(m2.RowInid) FROM [Practice].[dbo].[myTable] m2 WHERE M2.id = m1.id GROUP BY id) ORDER BY m1.id ASC

RANK() Over Partition BY not working

When I run the code below the ROWID is always 1.
I need to the ID to start at 1 for each item with the same Credit Value.
;WITH CTETotal AS (SELECT
TranRegion
,TranCustomer
,TranDocNo
,SUM(TranSale) 'CreditValue'
FROM dbo.Transactions
LEFT JOIN customers AS C
ON custregion = tranregion
AND custnumber = trancustomer
LEFT JOIN products AS P
ON prodcode = tranprodcode
GROUP BY
TranRegion
,TranCustomer
,TranDocNo)
SELECT
r.RegionDesc
,suppcodedesc
,t.tranreason as [Reason]
,t.trandocno as [Document Number]
,sum(tranqty) as Qty
,sum(tranmass) as Mass
,sum(transale) as Sale
,cte.CreditValue AS 'Credit Value'
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
FROM transactions t
LEFT JOIN dbo.Regions AS r
ON r.RegionCode = TranRegion
LEFT JOIN CTETotal AS cte
ON cte.TranRegion = t.TranRegion
AND cte.TranCustomer = t.TranCustomer
AND cte.TranDocNo = t.TranDocNo
GROUP BY
r.RegionDesc
,suppcodedesc
,t.tranreason
,t.trandocno
,cte.CreditValue
ORDER BY CreditValue ASC
EDIT
All the credit values with 400 must have the ROWID set to 1. And all the credit values with 200 must have the ROWID set to 2. And so on and so on.
Do you need something like this?
with cte (item,CreditValue)
as
(
select 'a',8 as CreditValue union all
select 'b',18 union all
select 'a',8 union all
select 'b',18 union all
select 'a',8
)
select CreditValue,dense_rank() OVER (ORDER BY item)AS ROWID from cte
Result
CreditValue ROWID
----------- --------------------
8 1
8 1
8 1
18 2
18 2
In your code replace
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
by
,DENSE_RANK() OVER (ORDER BY cte.CreditValue)AS ROWID
You just don't have to use PARTITION, just DENSE_RANK() OVER (ORDER BY cte.CreditValue)
I think the problem is with the RANK() OVER (PARTITION BY clause
you have to partition it by item not by CreditValue
Try this
RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.RegionDesc)AS ROWID
Edit: The issue here isn't actually the nesting of the subquery, it's potentially based on partition by having columns that truly make each row unique (or 1)
Rather than ranking within your complex query like this
select
rank() over(partition by...),
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
Try rank() or row_number() on the resulting data set, not within it.
For example, using the query above, remove rank() and implement it this way:
select
rank() over(partition by...),
results.*
from (
select
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
) as results

Resources