Insert last not null value in temp table by date - sql

I have this table for testing:
CREATE TABLE #ExchRates
(
[TimeId] int,
[CurrencyId] INT,
[ExchRate] DECIMAL(30,6)
)
INSERT INTO #ExchRates ([TimeId], [CurrencyId], [ExchRate])
VALUES
(
2017030500,
3,
6.142911
),
(
2017030600,
3,
6.152911
),
(
2017030700,
3,
NULL
),
(
2017030800,
3,
5.5
)
;
I want to insert values from this table in other table for one particular day(TimeId BETWEEN GETUTCDATE()-1 AND GETUTCDATE). Problem is when ExchRate is not set (NULL in table #ExchRate). In that case I want to use last known ExchRate for that currency. How can I solve this problem?

Try this-
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1
If you have more than one currency in the table, you can do this following -
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1

for the case of null you can use row_number() for getting the last value
select * from (select *,row_number() over(partition by CurrencyId order by TimeId desc) rn
from #ExchRates
) a where a.rn=1

Here's your query.
insert into Table2 ([TimeId], [CurrencyId], [ExchRate])
select ([TimeId], [CurrencyId], [ExchRate]),
isnull([ExchRate], (select top 1 [ExchRate] from #ExchRates order by [TimeId] desc)) from #ExchRates

Use ROW_NUMBER() to get the last record you want :
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeId DESC) rn
FROM #ExchRates )
SELECT
*
FROM CTE
WHERE rn = 1;

Related

Compare Column A of Row 1 with Column B of Row 2 in Same table

I have a table name 'Table A' where I need to get the all values based on two columns 'AdviserBusinessId' and 'ClientcontactGuid' having count > 1. I am able to achieve this using self join as below query.
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by gc.planenddate asc) as rownum from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
And this is what the table looks like:
[![enter image description here][1]][1]
Now my main point is that, I want to compare PlanEndDate of row 1 with PlanStartDate of row 2 and get the rows if PlanEndDate > PlanStartDate. Let's take an example of above two rows, if suppose the planstartdate was < planenddate then I just want to populate those above two rows.
Will cursor or loop be helpful in this ?
Thanks in advance. Any suggestions will be appreciated.
Use analytic functions:
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
rn
FROM (
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
ROW_NUMBER() OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS rn,
COUNT(*) OVER (
partition by adviserbusinessid, clientcontactguid
) AS num_rows,
LEAD(planStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_end
FROM GENIUS_ClientEngagement
) gce
WHERE num_rows > 1
AND ( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_end > planStartDate) )
You can use self join to achieve this. Something like this:
SELECT * FROM TableA A
LEFT JOIN TableA B ON A.ClientContactGuid = B.ClientContactGuid AND (A.RowNum+1) = B.RowNum
WHERE A.PlanEndDate>B.PlanStartDate OR B.PlanStartDate IS NULL
This was what I wanted, thanks to #MTO for the direction.
with cte
as(
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by planenddate desc) as rownum
from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1
) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
)
select *,ROW_NUMBER() over(partition by adviserbusinessid,clientcontactguid order by planenddate asc) as rn,
LEAD(PlanStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_ends into #temp2 from cte
where rownum <=2
select AdviserBusinessId,ClientContactGuid,PlanStartDate,PlanEndDate,ClientEngagementGuid,RenewalGuid from #temp2 where
( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_ends > planStartDate) )
drop table #temp2

SQL SERVER Update and Insert to different table that has duplicate value

I have two tables, Table A and B. I want to update the RAM_PARENT_CATEGORY_CODE column of Table A with the value from Table B. However, for category_alert_ctr 55 and 82. There are 2 possible RAM_PARENT_CATEGORY_CODE from Table B.
I want to insert a new row in Table A to accommodate both of those RAM_PARENT_CATEGORY_CODE (CRM1b and crm1c). Then update the value with the correct value from Table B.
So the expected result will be :
55 | crm1b1 | CRM1 | CRM1b
83 | crm1b1 | CRM1 | crm1c
82 | Area1 | BuildApp | OFC01
84 | Area1 | BuildApp | OFC02
Do you have any idea to do this? Thanks.
Use the MERGE statement to insert such rows from Table B that are not in Table A, and update those that are in Table A.To check, click here.
with
a as (
select
*,
row_number() over(
partition by category_alert_ctr order by (select 0)
) rn
from #A
),
b as (
select
*,
row_number() over(
partition by RAM_CATEGORY_CODE, RAM_GROUP
order by RAM_PARENT_CATEGORY_CODE
) rn,
row_number() over(
order by RAM_CATEGORY_CODE, RAM_PARENT_CATEGORY_CODE
) cac_offset
from #B
),
m as (
select
a.category_alert_ctr,
iif(b.rn = 1 and a.category_alert_ctr is not null,
a.category_alert_ctr,
max(a.category_alert_ctr) over() + b.cac_offset) new_cac,
b.RAM_CATEGORY_CODE, b.RAM_GROUP, b.RAM_PARENT_CATEGORY_CODE, b.rn
from b
left join a
on b.RAM_CATEGORY_CODE = a.ram_category_code and
b.RAM_GROUP = a.RAM_GROUP and b.rn = a.rn
)
merge a
using m
on a.RAM_CATEGORY_CODE = m.RAM_CATEGORY_CODE and
a.RAM_GROUP = m.RAM_GROUP and a.rn = m.rn
when matched then
update set
a.category_alert_ctr = m.new_cac,
a.RAM_PARENT_CATEGORY_CODE = m.RAM_PARENT_CATEGORY_CODE
when not matched then
insert(category_alert_ctr, ram_category_code,
RAM_GROUP, RAM_PARENT_CATEGORY_CODE)
values(m.new_cac, m.RAM_CATEGORY_CODE,
m.RAM_GROUP, m.RAM_PARENT_CATEGORY_CODE)
;
to handle multiple matches, use row_number() to generate a unique numbering for matching
UPDATE A
SET RAM_PARENT_CATEGORY_CODE = B.RAM_PARENT_CATEGORY_CODE
FROM (
SELECT *, RN = ROW_NUMBER() OVER (PARTITION BY RAM_CATEGORY_CODE, RAM_GROUP
ORDER BY RAM_CATEGORY_CODE)
FROM TABLEA
) A
INNER JOIN (
SELECT *, RN = ROW_NUMBER() OVER (PARTITION BY RAM_CATEGORY_CODE, RAM_GROUP
ORDER BY RAM_CATEGORY_CODE)
FROM TABLEB
) B
ON A.RAM_CATEGORY_CODE = B.RAM_CATEGORY_CODE
AND A.RAM_GROUP = B.RAM_GROUP
AND A.RN = B.RN
If necessary to update the category_alert_ctr column.To check, click here.
declare #A table(
category_alert_ctr int,
ram_category_code varchar(30),
RAM_GROUP varchar(30),
RAM_PARENT_CATEGORY_CODE varchar(30)
);
insert #A values
(25, 'HLTHLIC_FF', 'HEALTHLIC', null),
(28, 'M16', 'QBL', null),
(55, 'crm1b1', 'CRM1', null),
(55, 'crm1b1', 'CRM1', null),
(82, 'Area1', 'BuildApp', null),
(82, 'Area1', 'BuildApp', null);
declare #B table(
RAM_CATEGORY_CODE varchar(30),
RAM_GROUP varchar(30),
RAM_PARENT_CATEGORY_CODE varchar(30)
);
insert #B values
('HLTHLIC_FF', 'HEALTHLIC', 'HLTHLC_RST'),
('M16', 'QBL', 'EPA'),
('crm1b1', 'CRM1', 'CRM1b'),
('crm1b1', 'CRM1', 'crm1c'),
('Area1', 'BuildApp', 'OFC01'),
('Area1', 'BuildApp', 'OFC02');
with
a as (
select
*,
iif(
row_number() over(
partition by category_alert_ctr order by (select 0)
) = 1,
category_alert_ctr,
max(category_alert_ctr) over() +
row_number() over(order by category_alert_ctr) -
dense_rank() over(order by category_alert_ctr)
) new_category_alert_ctr,
row_number() over(
partition by category_alert_ctr order by (select 0)
) rn
from #A
),
b as (
select
*,
row_number() over(
partition by RAM_CATEGORY_CODE, RAM_GROUP
order by RAM_PARENT_CATEGORY_CODE
) rn
from #B
)
update a
set a.category_alert_ctr = a2.new_category_alert_ctr,
a.RAM_PARENT_CATEGORY_CODE = b.RAM_PARENT_CATEGORY_CODE
from a
join a a2
on a.category_alert_ctr = a2.category_alert_ctr and a.rn = a2.rn
join b
on a.RAM_CATEGORY_CODE = a.RAM_CATEGORY_CODE and
a.RAM_GROUP = b.RAM_GROUP and a.rn = b.rn
;
select * from #A;

Take the last record

I've a table like:
Create table Accounts
(
account_key char(2)
,account_name varchar(1024)
,type varchar(50)
,date_entered date
);
I need to select each account_name with the latest record. How this can be done? Desirable through Row_Number
WITH CTE AS
(
SELECT account_key, account_name, type, date_entered,
rn = row_number() over (partition by account_name order by date_entered desc)
FROM dbo.Accounts
)
SELECT account_key, account_name, type, date_entered
FROM CTE
WHERE RN = 1
You can do it like:
SELECT account_key, account_name, type, date_entered
from (
SELECT account_key,account_name,type,date_entered,
ROW_NUMBER() OVER (PARTITION BY date_entered DESC) AS RN
FROM Accounts
) X
WHERE X.RN=1

Get Second duplicate Record

I am getting after doing joins as ::
CompanyID EmpID Emp_no Location
-------------------- -------------------- ------------- -------------
1 24 100543 First.png
1 24 100543 Second.png
I want to select second Record i.e. Second.png by using CASE WHEN in select query.
Check this out.
declare #t table(CompanyID int, empid int, emp_no varchar(50), location varchar(100))
insert into #t values (1,24,100543,'First.png'),(1,24,100543,'Second.png'),(1,25,100544,'Second.png'),(1,25,100544,'First.png')
select * from
(
select
ROW_NUMBER() over(partition by companyid, empid order by companyid, empid ) rowno, *
from
#t
) a where rowno = 2 --and empid = 24 --here you can give empid to get particular employee detail
In case you want to get multiple empid's second entry in single select statement.
declare #t table(CompanyID int, empid int, emp_no varchar(50), location varchar(100))
insert into #t values (1,24,100543,'First.png'),(1,24,100543,'Second.png'),(1,25,100544,'Second.png'),(1,25,100544,'First.png')
,(1,26,100545,'First.png')
;with cte as
(
select
*
from
(
select
ROW_NUMBER() over(partition by empid order by empid ) rowno, *
from
#t
) a
),
cte1 as (
select
*,
ROW_NUMBER() OVER(PARTITION BY empid ORDER BY rowno DESC) as RN
from cte
)
select * from cte1 where rn = 1
You can write as:
;WITH CTE as
(
SELECT ROW_NUMBER() OVER ( PARTITION BY CompanyID,EmpID,Emp_no ORDER BY (SELECT 1))
AS rownum,CompanyID,EmpID,Emp_no,Location
FROM (SELECT * FROM #Test ) AS T
),CTE1 as
(
SELECT MAX(rownum) AS maxrownum,
CompanyID,
EmpID,
Emp_no
FROM CTE
GROUP BY CompanyID,EmpID,Emp_no
)
SELECT T.CompanyID,T.EmpID,T.Emp_no,T.Location
FROM CTE T
JOIN CTE1 T1 ON T.CompanyID = T1.CompanyID
AND T.EmpID = T1.EmpID
AND T.Emp_no = T1.Emp_no
AND T.rownum = T1.maxrownum
Explanation:
As there's no column like primary key through which we can identify
which row comes first you can write SELECT 1 in partition window.
Once you get rownumber for each combination of CompanyID,EmpID and Emp_no you can use second CTE to get the maxrow for each
combination
Just collect the data from the table for all rows with maxrownumbers
Hope this helps:)

SQL Server ROW_NUMBER() Issue

I'm using row_number() expression but I don't get result as I expected. I have a sql table and some rows are duplicate. They have same 'BATCHID' and I want to get second row number for these, for others I use first row number. How can I do it?
SELECT * FROM (SELECT * , ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY) Rn FROM SAYIMDCPC ) t
WHERE Rn=1
This code returns to me only first rows, but I want to get second rows for duplicated items.
ROW_NUMBER() gives every row a unique counter. You'd want to use RANK(), which is similar, but gives rows with identical values the same score:
SELECT *
FROM (SELECT * , RANK() OVER (PARTITION BY batchid ORDER BY scaqry) rk
FROM sayimdcpc) t
WHERE rk = 1
If some values are only shown once, but some twice (and perhaps more than twice), you don't want the "first" row, you want the "max" row. Try reversing your order condition:
SELECT *
FROM (SELECT * ,
ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY DESC) Rn
FROM SAYIMDCPC ) t
WHERE Rn=1
As a side note, it's still better to explicitly list out all columns; for instance, you probably don't need Rn outside of this query...
Simply try this,
SELECT * FROM (SELECT * , ROW_NUMBER() OVER (ORDER BY SCAQTY) Rn FROM SAYIMDCPC ) t
WHERE Rn=1
To rephrase it another way, it sounds like you're saying, "When there's a single row for the Batch ID, return the single row. When there are 2 or more rows, return the second row." That's going to require inspecting your Rn value to see what its max is. I don't think you can do it in a single query.
So I'd try something like this:
WITH NumberedRows AS (
SELECT * ,
ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY) Rn
FROM SAYIMDCPC
)
, MaxNumber AS (
SELECT Max(RN) as MaxRn,
BATCHID
FROM NumberedRows
GROUP BY BATCHID
)
, NonDupes AS (
SELECT *
FROM NumberedRows
WHERE BATCHID NOT IN (SELECT BATCHID FROM MaxNumber WHERE MaxNumber = 1)
)
, SecondRows AS (
SELECT (
FROM NumberedRows
WHERE BATCHID NOT IN (SELECT BATCHID FROM MaxNumber WHERE MaxNumber > 1)
AND Rn = 2
)
SELECT
FROM NonDupes
UNION ALL
SELECT *
FROM SecondRows
Please try this. It will select max row num, if no duplicate then it should be first one otherwise second
select * from (SELECT * , ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY) Rn FROM SAYIMDCPC ) d,
(SELECT batchid,max(Rn) maxRn FROM (SELECT * , ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY) Rn FROM SAYIMDCPC ) t
group by batchid) q
where d.batchid = q.batchid and d.rn = q.maxrn
correct me if i am wrong
e.g sample data
BatchID, SCAQTY
1 , 10
2 , 10
2 , 20
2 , 30
is your expectation result like below?
**Expectation Result 1**
BatchID , SCAQty
1 , 10
2 , 30
or
**Expectation Result 2**
BatchID , SCAQty
1 , 10
2 , 20
2 , 30
based on my understanding what you want to perform is Expectation Result 1, so i guess Query below should able to help u, you just need to add desc for SCAQTY in your query
SELECT * FROM (SELECT * ,
ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY DESC) Rn FROM SAYIMDCPC ) t
WHERE Rn=1
Total result set with duplicates and non duplicates. The first column "IsDuplicate" indicates if the column is a duplicate or not.
;WITH d1 AS (
SELECT Seq = ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY)
,*
FROM SAYIMDCPC
)
SELECT IsDuplicate = CONVERT(BIT, Seq)
,*
FROM d1
This will give you only the duplicates:
;WITH d1 AS (
SELECT Seq = ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY)
,*
FROM SAYIMDCPC
)
SELECT IsDuplicate = CONVERT(BIT, Seq)
,*
FROM d1
WHERE Seq > 1
This will give you only the non duplicates (as in your first query)
;WITH d1 AS (
SELECT Seq = ROW_NUMBER() OVER (PARTITION BY BATCHID ORDER BY SCAQTY)
,*
FROM SAYIMDCPC
)
SELECT IsDuplicate = CONVERT(BIT, Seq)
,*
FROM d1
WHERE Seq = 1