I have a table in which I have few columns like below:
Cusnbr Name LoadNumber
1 Z 10
1 Z 9
1 Z 8
1 C 7
1 C 6
1 C 5
1 B 4
1 B 3
1 A 2
1 A 1
it is just for one cusnbr there are million of cusnbr like this..
I want output like below
Cusnbr Name LoadNumber
1 C 7
1 B 4
1 A 2
For that I write below query in sql server 2008:
;With x as
(
Select * ,rn=Row_number() over (order by cusnbr,loadnumber) from table
)
select x.* from x left outer join x as y on x.rn=y.rn+1
and x.name<>y.name where y.name is not null
but I am not getting the desired output in the above code I am getting last Z also which I don't want and I am getting irregular data not in the correct form in which I want
Any help will be appreciated !!
like this I want but not able to get the desired output
I use this example
Though the question is not clear to me , Guessing from the output I have tried out Dense Rank . I guessed you want the record with highest LoadNumber with the same name .
Select * from cteTrial where LoadNumber in (
Select MAX(x.LoadNumber) as LoadNumber from (
Select cusnbr , name , LoadNumber , DENSE_RANK() over (order by Name desc )
as Dense from cteTrial) as x group by x.Dense
)
If you can use CTE it will produce better performance .
i written the code as per expected
;With cte(Cusnbr , Name , LoadNumber)
AS
(
SELECT 1,'Z', 10 Union all
SELECT 1,'Z', 9 Union all
SELECT 1,'Z', 8 Union all
SELECT 1,'C', 7 Union all
SELECT 1,'C', 6 Union all
SELECT 1,'C', 5 Union all
SELECT 1,'B', 4 Union all
SELECT 1,'B', 3 Union all
SELECT 1,'A', 2 Union all
SELECT 1,'A', 1
)
SELECT cusnbr,
NAME,
loadnumber
FROM (SELECT *,
Row_number()
OVER(
partition BY NAME
ORDER BY loadnumber DESC) AS RNk,
Row_number()
OVER(
ORDER BY (SELECT 1)) - 1 AS RNO
FROM (SELECT *
FROM cte)dt)DT2
WHERE DT2.rnk = 1
AND rno > 0
ORDER BY NAME DESC
Result
cusnbr NAME loadnumber
-------------------------
1 C 7
1 B 4
1 A 2
Related
I have 2 tables in SQL Server and I want to compare them. I want to take 'NEEDED_AMOUNT' and 'min. 'ID'. I tried the following:
SELECT S_ID, NEEDED_AMOUNT, ID
FROM (
select T1.S_ID
, T2.NEEDED_AMOUNT
, T1.ID
from T1
INNER JOIN T2 MSD ON T1.S_ID = T2.S_ID
) TABLE1
GROUP BY S_ID, NEEDED_AMOUNT, ID
To explain this for example: in T1 table I have S_ID as '1' and its amount '20' and '30'. Also in T2 I have request for S_ID and I need '40' amount. So in T1 table how can I reach 40? I must take first row '20' amount and I split second row '30' to '20'. Below you can see what I want the output.
So here are the tables.
I can call this table T1 (ID is primary key and auto inc.):
ID AMOUNT S_ID
1 20 1
2 30 1
3 10 2
4 20 3
5 5 3
and I can call this table T2:
S_ID NEEDED_AMOUNT DATE
1 40 01.01.2020
2 5 02.01.2020
3 20 03.01.2020
So my output will be like this:
S_ID NEEDED_AMOUNT ID
1 20 1
1 20 2
2 5 3
3 20 4
Thanks for any opinion
I would use recursive approach for this :
with cte as (
select id, amount, s_id, needed_amount,
(case when amount = needed_amount then 1 else cnt end) as cnt
from (select t1.*, t2.needed_amount,
row_number() over (partition by t1.s_id order by t1.id) as seq,
count(*) over (partition by t1.s_id) as cnt
from t1 inner join
t2
on t2.s_id = t1.s_id
) t
where seq = 1
), cte1 as (
select c.needed_amount / c.cnt as amount, c.s_id, 1 as start, c.cnt
from cte c
union all
select amount, s_id, start + 1, cnt
from cte1 c1
where start < cnt
)
select s_id, amount, row_number() over (order by s_id) as id
from cte1;
I have list of sample data. Using this I need new column which having sequence number. But condition of this sequence number is if consecutively InRange column value 1 then only it generate sequence number.In between if InRange value 0 then again sequence number start from 1 and so on.
Below query which I have created but not return expected result.
CREATE TABLE #Result (ID INT,Value INT,InRange BIT)
INSERT INTO #Result
SELECT 1 ,211,0
UNION SELECT 2 ,205,1
UNION SELECT 3 ,214,0
UNION SELECT 4 ,202,1
UNION SELECT 5 ,204,1
UNION SELECT 6 ,203,1
UNION SELECT 7 ,209,0
UNION SELECT 8 ,216,0
UNION SELECT 9 ,205,1
UNION SELECT 10 ,224,0
Query:
SELECT *
,CASE WHEN InRange=1 THEN ROW_NUMBER()OVER(Order by Id asc) ELSE 0 END AS ExpectedColumn
FROM #Result
Expected result.
ID Value InRange ExpectedColumn
1 211 0 0
2 205 1 1
3 214 0 0
4 202 1 1
5 204 1 2
6 203 1 3
7 209 0 0
8 216 0 0
9 205 1 1
10 224 0 0
This is a gaps and islands problem, with the islands being each group of records to which you want to assign its own row number sequence. One straightforward way to handle this uses the difference in row numbers method:
WITH cte1 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY ID) rn1
FROM #Result
WHERE InRange = 1
),
cte2 AS (
SELECT t1.*,
ROW_NUMBER() OVER (ORDER BY t1.ID) - t2.rn1 AS diff
FROM #Result t1
LEFT JOIN cte1 t2
ON t1.ID = t2.ID
)
SELECT ID, Value, InRange,
CASE WHEN InRange <> 0
THEN ROW_NUMBER() OVER (PARTITION BY diff ORDER BY ID)
ELSE 0 END AS ExpectedColumn
FROM cte2
ORDER BY ID;
Demo
with grouped_data as (
select
*,
count(case when InRange = 0 then 1 else null end) over(order by ID rows between unbounded preceding and current row) as group_number
from #Result
)
select
ID,
Value,
InRange,
row_number() over(partition by group_number order by ID) - 1 as expected_column
from grouped_data
order by ID;
I have a below dataset and I am trying to get max occurrences of CID per each OID.
IF OBJECT_ID('TEMPDB..#SS',N'U') IS NOT NULL
DROP TABLE #SS
GO
SELECT * INTO #SS FROM (
SELECT 1 AS OID,501 AS CID
UNION ALL
SELECT 1 AS OID,503 AS CID
UNION ALL
SELECT 1 AS OID,502 AS CID
UNION ALL
SELECT 1 AS OID,501 AS CID
UNION ALL
SELECT 1 AS OID,501 AS CID
UNION ALL
SELECT 2 AS OID,502 AS CID
UNION ALL
SELECT 2 AS OID,502 AS CID
UNION ALL
SELECT 2 AS OID,502 AS CID
UNION ALL
SELECT 2 AS OID,501 AS CID
UNION ALL
SELECT 1 AS OID,503 AS CID
)A
GO
In above sample dataset, I need to get 2 CID per each OID which occurred maximum times. The expected result could be:
OID CID
1 501
1 503
2 501
2 502
This cannot be a duplicate to SQL Select top frequent records because I need this sub-queries and SQL-Server would not accept ORDER BY in sub-query and eventually I need a ranking function to solve my issue. Ranking function was not used in the link provided.
You can do this pretty easily utilizing ROW_NUMBER. Thanks for Tab Alleman for the clarification on your requirements.
select *
from
(
select *
, RowNum = ROW_NUMBER() over (partition by OID order by count(*) desc)
from #SS
group by OID
, CID
) x
where x.RowNum <= 2
order by x.OID
, x.CID
I have data similar to below. I need to group the status column based on the occurrence of data.
Id Status Value
1 K 1
2 K 3
3 K 2
4 B 2
5 B 3
6 K 6
7 J 5
8 J 2
I want data as below
Status Value
K 6
B 5
K 6
J 7
I need the cumulative sum of the value column.In the status column if the data is same consecutively, then I need to add the value columns. I cannot apply group by. In the example given K is repeated twice, because they are not consecutive.
I have tried below query, but it doesn't work as required.
select Status,
(select sum(value)
from table t2
where
t2.Status = t.Status and
t2.SNO <= t.SNO
) as total
from table t;
This is a Gaps and Islands Question
I tackle these by using the incrementing Id and combing this with ROW_NUMBER window function
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.Status ORDER BY X.Id)
, X.Id
, X.Status
, X.Value
FROM
cteX X
ORDER BY
X.Id
This gives this result set, note the Grp column
Grp Id Status Value
------- ------- ------- -------
0 1 K 1
0 2 K 3
0 3 K 2
3 4 B 2
3 5 B 3
2 6 K 6
6 7 J 5
6 8 J 2
Then combine with a CTE or derived table you can get your expected output
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT Y.Status
, Value = SUM(Y.Value)
FROM
(
SELECT TOP 100 PERCENT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.Status ORDER BY X.Id)
, X.Id
, X.Status
, X.Value
FROM
cteX X
ORDER BY
X.Id
) Y
GROUP BY
Y.Grp, Y.Status
Output
Status Value
------- -------
B 5
J 7
K 6
K 6
Update Question include "Preserve order" solution
Just include an Order by MIN(Id)
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT
Y.[Status]
,[Value] = SUM(Y.[Value])
FROM
(
SELECT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.[Status] ORDER BY X.Id)
, X.Id
, X.[Status]
, X.[Value]
FROM
cteX X
) Y
GROUP BY
Y.Grp, Y.[Status]
ORDER BY
MIN(Y.Id) --preserve the Status Order
Output
Status Value
------- -------
K 6
B 5
K 6
J 7
I have a table as below
Id RFrom RTo
.... ....... .....
1 10 14
1 22 25
2 100 102
2 176 180
I want to get all numbers between each RFrom and RTo for each Id. My expected result is as follows
Id NUMS
.... ......
1 10
1 11
1 12
1 13
1 14
1 22
1 23
1 24
1 25
2 100
2 101
2 102
2 176
2 177
2 178
2 179
2 180
Do I have to use cursor to achieve this?
Here is your sample table
SELECT * INTO #TEMP FROM
(
SELECT 1 ID, 10 RFROM, 14 RTO
UNION ALL
SELECT 1, 22, 25
UNION ALL
SELECT 2, 100, 102
UNION ALL
SELECT 2, 176, 180
)TAB
You need to use recursion for each Id to get the result
;WITH CTE AS
(
SELECT ID,RFROM RFROM1,RTO RTO1
FROM #TEMP
UNION ALL
SELECT T.ID,RFROM1+1,RTO1
FROM #TEMP T
JOIN CTE ON CTE.ID = T.ID
WHERE RFROM1 < RTO1
)
SELECT DISTINCT ID,RFROM1 NUMS
FROM CTE
SQL FIDDLE
Another option would be to use a numbers table with a join -- recursion can be time consuming.
There are several options to create a numbers table (I'd recommend creating a permanent one), but here's a temp one created with a common-table-expression:
with numberstable as (
select top 10000 row_number() over(order by t1.number) as number
from master..spt_values t1
cross join master..spt_values t2
)
select yt.id,
nt.number
from yourtable yt
join numberstable nt on nt.number between yt.rfrom and yt.rto
SQL Fiddle Demo
Create a tally table using stacked CTE which will have better performance when compared to recursive CTE
declare #min int
select #min= min(RFrom) from yourtable
;WITH e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2) -- 10*100
SELECT b.id,
a.n
FROM yourtable b
JOIN (SELECT n = Row_number()OVER (ORDER BY n)+ #min-1
FROM e3)a
ON a.n BETWEEN b.RFrom AND b.RTo
ORDER BY n;
Check here for info