Unable to get desired output using Dense Rank - sql-server

Can you please help me how to get the expected output as shown in the screenshot below?
DECLARE #TT TABLE ( CUSTOMERID INT, TYPE VARCHAR(100) , D1 DATE)
INSERT INTO #TT VALUES ( 15001,'TYPE1', '4/1/2017')
INSERT INTO #TT VALUES ( 15001,'TYPE1', '4/2/2017')
INSERT INTO #TT VALUES ( 15001,'TYPE1', '4/3/2017')
INSERT INTO #TT VALUES ( 15001,'NON TYPE1', '4/4/2017')
INSERT INTO #TT VALUES ( 15001,'NON TYPE1', '4/5/2017')
INSERT INTO #TT VALUES ( 15001,'NON TYPE1', '4/6/2017')
INSERT INTO #TT VALUES ( 245,'Non TYPE1', '4/1/2017')
INSERT INTO #TT VALUES ( 245,'Non TYPE1', '4/2/2017')
INSERT INTO #TT VALUES ( 245,'Non TYPE1', '4/3/2017')
INSERT INTO #TT VALUES ( 245,'TYPE1', '4/4/2017')
INSERT INTO #TT VALUES ( 245,'TYPE1', '4/5/2017')
INSERT INTO #TT VALUES ( 245,'TYPE1', '4/6/2017')
A query is:
SELECT * ,
DENSE_RANK() OVER ( PARTITION BY CUSTOMERID ORDER BY CUSTOMERID,TYPE) DR
FROM #TT
WHERE CUSTOMERID = 15001
ORDER BY CUSTOMERID,D1
SELECT *,
DENSE_RANK() OVER ( PARTITION BY CUSTOMERID ORDER BY CUSTOMERID,TYPE) DR
FROM #TT
WHERE CUSTOMERID = 245
ORDER BY CUSTOMERID,D1
Thank you for the help.

You want to order groups by the minimum date. I think it is something like this:
SELECT t.*,
DENSE_RANK() OVER ( PARTITION BY CUSTOMERID ORDER BY mind1, TYPE) DR
FROM (SELECT t.*, MIN(d1) OVER (PARTITION BY CUSTOMERID, TYPE) as mind1
FROM #TT t
) t
WHERE CUSTOMERID = 15001
ORDER BY CUSTOMERID, D1;
This sort of assumes that the types are not interleaved (as in your examples). If that is the case, then please ask another question. That significantly changes the question. That question should also provide better sample data and desired results.

Related

Filling the ID column of a table NOT using a cursor

Tables have been created and used without and ID column, but ID column is now needed. (classic)
I heard everything could be done without cursors. I just need every row to contain a different int value so I was looking for some kind of row number function :
How do I use ROW_NUMBER()?
I can't tell exactly how to use it even with these exemples.
UPDATE [TableA]
SET [id] = (select ROW_NUMBER() over (order by id) from [TableA])
Subquery returned more than 1 value.
So... yes of course it return more than one value. Then how to mix both update and row number to get that column filled ?
PS. I don't need a precise order, just unique values. I also wonder if ROW_NUMBER() is appropriate in this situation...
You can use a CTE for the update
Example
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey')
;with cte as (
Select *
,RN = Row_Number() over(Order by (Select null))
From #TableA
)
Update cte set ID=RN
Select * from #TableA
Updated Table
ID SomeCol
1 Dog
2 Cat
3 Monkey
You can use a subquery too as
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey');
UPDATE T1
SET T1.ID = T2.RN
FROM #TableA T1 JOIN
(
SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 1)) RN,
*
FROM #TableA
) T2
ON T1.SomeCol = T2.SomeCol;
Select * from #TableA

How to write a SQL script that deletes duplicate posts

I have a table with these columns:
id (pk, int identity), imei (varchar), name (varchar), lastconnected (datetime)
Some of the entries in this table have the same name and imei, but different id and different lastconnected date.
How can I effectively filter out all entries that have duplicates (with a SQL script), and then delete the one with the latest lastconnected date?
A simple ROW_NUMBER and DELETE should do the trick:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY imei, [name] ORDER BY lastconnected DESC)
FROM dbo.YourTable
)
DELETE FROM CTE
WHERE RN = 1;
This is easy and will solve your problem
DECLARE #table TABLE
(
id int,
name varchar(10),
imei varchar(10)
)
insert into #table select 1, 'a','a'
insert into #table select 2, 'b','a'
insert into #table select 3, 'c','a'
insert into #table select 4, 'a','a'
insert into #table select 5, 'c','a'
insert into #table select 6, 'a','a'
insert into #table select 7, 'c','a'
insert into #table select 8, 'a','a'
WHILE (exists (select '' from #table group by name , imei having count(*) > 1))
BEGIN
delete from #table where id in (
select max(id) from #table group by imei , name having count(*) > 1)
End
select * from #table
My first instinct is to use RANK(). This will delete all duplicates, not just the most recent, in cases where things are duplicated multiple times.
delete a
from (
select id, imei, name, lastconnected, RANK() over(partition by imei, name order by lastconnected) as [rank] from #temp
) as a
where a.rank>1
It selects the maximum of the date for each combination of name and iemi and then deletes that particular row.
DELETE FROM yourtablee
WHERE (lastconnecteddate,name,imei) in
(SELECT max(lastconnecteddate), name,imei
FROM yourtable
GROUP BY name,imei)

SQL pivot not handling absence of data

I have a table
Create table dbo.temp(ID int, ExpenseID int, ExpenseName Varchar(100) null, ExpenseDate date null, Value decimal(19,4) null)
Insert into dbo.temp values(1,100,'CostClothes','2015-01-01',100.0000)
Insert into dbo.temp values(1,200,'Discount','2015-01-01',1.0000)
Insert into dbo.temp values(2,100,'CostClothes','2016-01-01',250.0000)
Insert into dbo.temp values(2,200,'Discount','2016-01-01',1.0000)
Insert into dbo.temp values(1,100,'CostClothes','2014-01-01',500.0000)
Insert into dbo.temp values(2,200,'Discount','2014-01-01',5.0000)
Now I want to pivot this table on ExpenseID and the expected output is
Create table dbo.output(ID int, CostClothes decimal(19,4) null, Discount decimal(19,4) null, ExpenseDate date null)
insert into dbo.output values (1,100.0000,1.0000,'2015-01-01')
insert into dbo.output values (1,500.0000,NULL,'2014-01-01')
insert into dbo.output values (2,NULL,5.0000,'2014-01-01')
insert into dbo.output values (2,100.0000,1.0000,'2016-01-01')
This is what I have and i am not getting correct output
SELECT ID,ISNULL([100],0) as CostClothes,ISNULL([200],0) as Discount,expenseDate
FROM
(
SELECT * FROM dbo.temp
) AS p
PIVOT
(
MAX(Value) for ExpenseID in ([100],[200])
) AS PV1
How do I change the query
Thanks
MR
Given the sample data, you can either do a pivot with an aggregation, or just a simple conditional aggregation.
select
ID
,max(case when ExpenseName = 'CostClothes' then Value end) as CostClothes
,max(case when ExpenseName = 'Discount' then Value end) as Discount
,ExpenseDate
from
dbo.temp
group by
ID
,ExpenseDate
order by
ID
Pivot Method
select
ID
,CostClothes = max(CostClothes)
,Discount = max(Discount)
,ExpenseDate
from
dbo.temp
pivot(
max(Value) for ExpenseName in (CostClothes, Discount)
) p
group by
ID
,ExpenseDate
order by
ID
Demo: http://rextester.com/ENHTIK13664
Your problem is that you're selecting too much information in your derived table.
If you're going to use Select *, you don't even need a derived table. When using a PIVOT, you should select only the fields you need in your final result. The same way you would write the conditional aggregation query.
SELECT ID,
ISNULL([100], 0) AS CostClothes,
ISNULL([200], 0) AS Discount,
expenseDate
FROM
(
SELECT ID,
ExpenseID,
ExpenseDate,
Value
FROM temp
) AS p PIVOT(MAX(Value) FOR ExpenseID IN([100],[200])) AS PV1
This should give you the result you want by eliminating the ExpenseName column. Or you could use the ExpenseName column and eliminate the ExpenseID column

How to Update a table while sorting based on Date column in SQL?

The first column of a table is the date.
I need to sort the rest of the data while actually updating the table according to date (descending). I can't use UPDATE and ORDER BY together.
I tried using something similar to this post:
UPDATE Test
SET Number = rowNumber
FROM Test
INNER JOIN
(SELECT ID, row_number() OVER (ORDER BY ID DESC) as rowNumber
FROM Test) drRowNumbers ON drRowNumbers.ID = Test.ID
in
SQL Server: UPDATE a table by using ORDER BY
But I cannot mix row_number and date.
Any help will be appreciated.
Use a CTE:
Check it here: http://rextester.com/NGTM78965
create table #t1 (id int, d datetime, rown int);
insert into #t1 values (1,'2016-05-01',0);
insert into #t1 values (2,'2016-05-04',0);
insert into #t1 values (3,'2016-06-01',0);
insert into #t1 values (4,'2016-04-03',0);
insert into #t1 values (5,'2016-05-12',0);
insert into #t1 values (6,'2016-08-01',0);
insert into #t1 values (7,'2016-05-15',0);
insert into #t1 values (8,'2016-05-25',0);
with cte (id, d, r) as
(
select id, d, row_number() over (order by d) r
from #t1
)
update #t1
set #t1.rown = cte.r
from cte inner join #t1 on #t1.id = cte.id;
select * from #t1 order by d

SQL Server Another simple question

I have 2 temp Tables [Description] and [Institution], I want to have these two in one table.
They are both tables that look like this:
Table1; #T1
|Description|
blabla
blahblah
blagblag
Table2; #T2
|Institution|
Inst1
Inst2
Inst3
I want to get it like this:
Table3; #T3
|Description| |Institution|
blabla Inst1
blahblah Inst2
blagblag Inst3
They are already in sort order.
I just need to get them next to each other..
Last time I asked was something almost the same.
I used this query
Create Table #T3
(
[From] Datetime
,[To] Datetime
)
INSERT INTO #T3
SELECT #T1.[From]
, MIN(#T2.[To])
FROM #T1
JOIN #T2 ON #T1.[From] < #T2.[To]
GROUP BY #T1.[From]
Select * from #T3
It did work for the date values, but it won't work here ? :s
Thank you.
One thing that concerns me is that you say that the values "are already in sort order". There really is no default sort order -- if you don't specify a sort order, you are at the mercy of SQL Server to determine the order in which the data is returned. The solution below assumes that there is some way to sort the data such that the records "match up" (using the ORDER BY clauses).
Hope this helps,
John
-- Table 1 test data
Create Table #T1
(
[Description] nvarchar(30)
)
INSERT INTO #T1 ([Description]) VALUES ('desc1')
INSERT INTO #T1 ([Description]) VALUES ('desc2')
INSERT INTO #T1 ([Description]) VALUES ('desc3')
-- Table 2 test data
Create Table #T2
(
[Institution] nvarchar(30)
)
INSERT INTO #T2 (Institution) VALUES ('Inst1')
INSERT INTO #T2 (Institution) VALUES ('Inst2')
INSERT INTO #T2 (Institution) VALUES ('Inst3')
-- Create table 3
Create Table #T3
(
[Description] nvarchar(30),
[Institution] nvarchar(30)
);
-- Use CTE2 to add row numbers to the data; use the row numbers to join the tables
-- you must specify the sort order for the data in the tables
WITH CTE1 (Description, RowNum) AS
(
SELECT [Description], ROW_NUMBER() OVER(ORDER BY [Description]) as RowNum
FROM #T1
),
CTE2 (Institution, RowNum) AS
(
SELECT Institution, ROW_NUMBER() OVER(ORDER BY Institution) as RowNum
FROM #T2
)
INSERT INTO #T3
SELECT CTE1.Description, CTE2.Institution
FROM CTE1
LEFT JOIN CTE2 ON CTE1.RowNum = CTE2.RowNum
Select * from #T3

Resources