SQL Server : reset Id and recreate data - sql

I am looking for a way to reset primary key Ids and recreate data so they are sorted by date.
Before
Pk_Col Letters_Col Date_Col
------------------------------------------
1 A 2015-02-16 00:00:00.000
2 B 2012-02-16 00:00:00.000
3 C 2014-02-16 00:00:00.000
1003 D 2009-02-16 00:00:00.000
1004 E 2008-02-16 00:00:00.000
1902 F 2016-02-16 00:00:00.000
After / desired output
Pk_Col Letters_Col Date_Col
------------------------------------------
1 E 2008-02-16 00:00:00.000
2 D 2009-02-16 00:00:00.000
3 B 2012-02-16 00:00:00.000
4 C 2014-02-16 00:00:00.000
5 A 2015-02-16 00:00:00.000
6 F 2016-02-16 00:00:00.000
I've tried so far:
DBCC CHECKIDENT ('dbo.myTable',RESEED,0);
INSERT INTO dbo.myTable (Letters_Col, Date_Col)
SELECT
Letters_Col, Date_Col
FROM
(DELETE FROM myTable OUTPUT deleted.*) d;
I have to include query below probably but I had no luck to run this query successfully with recreating data and sorting at one time:
select *
from myTable
order by cast([Date_Col] as datetime) asc

It can be dangerous to reset primary keys. After all, they are used for foreign key relationships, so another table might be referencing them. And, the key itself should not have any particular meaning.
However, you can do what you want using ranking functions and update:
with toupdate as (
select t.*, row_number() over (order by date) as seqnum
from myTable t
)
update toupdate
set pk_Col = seqnum;

If you want to update PK_Col and there isn't any foreign key:
UPDATE dbo.myTable
SET PK_Col = (SELECT COUNT(*)
FROM dbo.myTable ti
WHERE ti.DateCol <= dbo.myTable.DateCol And
ti.PK_Col <= dbo.myTable.PK_Col)

Related

T-SQL get values for specific group

I have a table EmployeeContract similar like this:
ContractId
EmployeeId
ValidFrom
ValidTo
Salary
12
5
2018-02-01
2019-06-31
x
25
8
2015-01-01
2099-12-31
x
50
5
2019-07-01
2021-05-31
x
52
6
2011-08-01
2021-12-31
x
72
8
2010-08-01
2014-12-31
x
52
6
2011-08-01
2021-12-31
x
Table includes history contracts in company for each employee. I need to get date when employees started work and last date of contract. Sometime records has duplicates.
For example, based on data from above:
EmployeeId
ValidFrom
ValidTo
5
2018-02-01
2021-05-31
8
2010-08-01
2099-12-31
6
2011-08-01
2021-12-31
Base on this article: https://www.techcoil.com/blog/sql-statement-for-selecting-the-latest-record-in-each-group/
I prepared query like this:
select minv.*, maxv.maxvalidto from
(select distinct con.[EmployeeId], mvt.maxvalidto
from [EmployeeContract] con
join (select [EmployeeId], max(validto) as maxvalidto
FROM [EmployeeContract]
group by [EmployeeId]) mvt
on con.[EmployeeId] = mvt.[EmployeeId] and mvt.maxvalidto = con.validto) maxv
join
(select distinct con.[EmployeeId], mvf.minvalidfrom
from [EmployeeContract] con
join (select [EmployeeId], min(validfrom) as minvalidfrom
FROM [EmployeeContract]
group by [EmployeeId]) mvf
on con.[EmployeeId] = mvf.[EmployeeId] and mvf.minvalidfrom = con.validfrom) minv
on minv.[EmployeeId] = maxv.[EmployeeId]
order by 1
But I'm not satisfied, i think it's not easy to read, and probably optimize is poor. How can I do it better?
I think you want group by:
select employeeid, min(validfrom), max(validto)
from employeecontract
group by employeeid

create a row index column beginning at -1

I need to create a row index column that begins at -1 so i can query the previous day's balance. My current query:
select TRANSDATE, sum(convert(float,AMOUNTMST-SETTLEAMOUNTMST)) as Balance
from [AX2cTestStage].[dbo].[CUSTTRANS_V]
group by TRANSDATE
order by TRANSDATE asc
TRANSDATE Balance
2019-04-12 00:00:00.000 -22591.47
2019-04-15 00:00:00.000 -394.95
2019-04-25 00:00:00.000 -1776
2019-04-26 00:00:00.000 -11973.84
2019-04-29 00:00:00.000 -24230.16
2019-05-02 00:00:00.000 -10695.39
This is what i need:
TRANSDATE Balance Row Index
2019-04-12 00:00:00.000 -22591.47 -1
2019-04-15 00:00:00.000 -394.95 0
2019-04-25 00:00:00.000 -1776 1
2019-04-26 00:00:00.000 -11973.84 2
2019-04-29 00:00:00.000 -24230.16 3
2019-05-02 00:00:00.000 -10695.39 4
I have tried to declare a variable as the row index
declare #row_num as int = -1
select TRANSDATE, sum(convert(float,AMOUNTMST-SETTLEAMOUNTMST)) as Balance, #row_num += 1 as Row Index
from [AX2cTestStage].[dbo].[CUSTTRANS_V]
group by TRANSDATE
i receive this error:
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
after declaring a variable for each field I still receives errors. Is there an easier way to accomplish this? thanks
You can use ROW_NUMBER(). For example:
select
TRANSDATE,
sum(convert(float,AMOUNTMST-SETTLEAMOUNTMST)) as Balance,
row_number() over(order by TRANSDATE) - 2 as Row Index
from [AX2cTestStage].[dbo].[CUSTTRANS_V]
group by TRANSDATE

Select next subsequent change of certain column in a new column

I have a table with a unique index on Contracts of Customers that live in Houses. I want to know the days per house how long it takes when someone moves out (Contract end date) and a new contracts starts. For that I want to know what the first next contract will be in that house, but on the same row as the old contract for a (potentially different) customer.
This how the table currently looks like, I select the top 10 here:
SELECT TOP 10
PMCCONTRACT.ACCOUNTNUM --Customer
,PMCCONTRACT.RENTALOBJECTID --House
,PMCCONTRACT.CONTRACTID --Contract & Unique index of the table
,PMCCONTRACT.VALIDFROM --Contract Start Date
,PMCCONTRACT.VALIDTO --Contract End Date
FROM PMCCONTRACT
Then this rolls out:
ACCOUNTNUM RENTALOBJECTID CONTRACTID VALIDFROM VALIDTO
101852 2488 HC000001 1994-03-01 00:00:00.000 NULL
101136 2489 HC000002 1920-01-01 00:00:00.000 NULL
101352 2491 HC000003 1996-09-16 00:00:00.000 NULL
100687 2492 HC000004 1984-11-01 00:00:00.000 NULL
105160 2499 HC000005 1975-05-02 00:00:00.000 2018-01-31 00:00:00.000
102821 2501 HC000006 1997-09-16 00:00:00.000 NULL
100731 2506 HC000007 1920-01-01 00:00:00.000 2018-11-15 00:00:00.000
102797 2508 HC000008 1998-02-01 00:00:00.000 NULL
102155 2512 HC000009 1981-09-01 00:00:00.000 NULL
102563 2515 HC000010 1965-10-17 00:00:00.000 2017-06-30 00:00:00.000
And what I want is that based on the RENTALOBJECTID it will show what the First Next contract on that house was (so it is important that the CONTRACTID remains unique in this table).
Below is the code I use to get it, however, it shows all the following contract changes for that specific RENTALOBJECTID (House).
SELECT --TOP 1000
PMCCONTRACT.CONTRACTID
,PMCCONTRACT.RENTALOBJECTID
,PMCCONTRACT.VALIDFROM
,PMCCONTRACT.VALIDTO
,P2.CONTRACTID AS 'FirstNextContractId'
,P2.VALIDFROM
,P2.VALIDTO
FROM PMCCONTRACT
LEFT JOIN PMCCONTRACT P2
ON PMCCONTRACT.RENTALOBJECTID = P2.RENTALOBJECTID
LEFT JOIN
(SELECT
RENTALOBJECTID,
MAX(CONTRACTID) AS CONTRACTID
FROM PMCCONTRACT
GROUP BY RENTALOBJECTID) X ON X.CONTRACTID = P2.CONTRACTID
WHERE P2.VALIDFROM > PMCCONTRACT.VALIDTO
This is what I get when I select only ContractID HC000028, it shows 2 rows, while I want it to show only the first row.
CONTRACTID RENTALOBJECTID VALIDFROM VALIDTO FirstNextContractId VALIDFROM2 VALIDTO2
HC000028 75 1995-01-01 00:00:00.000 2016-04-30 00:00:00.000 HC009990 2016-05-01 00:00:00.000 2018-11-25 00:00:00.000 --<< Only row I want to show
HC000028 75 1995-01-01 00:00:00.000 2016-04-30 00:00:00.000 HC025218 2018-11-26 00:00:00.000 1900-01-01 00:00:00.000 --Too far in the future
Kind regards,
Igor
It looks like a simple LEAD window function is enough. It returns the next row, as defined by partitioning and ordering clauses.
SELECT TOP 10
PMCCONTRACT.ACCOUNTNUM --Customer
,PMCCONTRACT.RENTALOBJECTID --House
,PMCCONTRACT.CONTRACTID --Contract & Unique index of the table
,PMCCONTRACT.VALIDFROM --Contract Start Date
,PMCCONTRACT.VALIDTO --Contract End Date
,LEAD(CONTRACTID) OVER (PARTITION BY RENTALOBJECTID ORDER BY VALIDFROM) AS NextContractID
,LEAD(VALIDFROM) OVER (PARTITION BY RENTALOBJECTID ORDER BY VALIDFROM) AS NextVALIDFROM
,LEAD(VALIDTO) OVER (PARTITION BY RENTALOBJECTID ORDER BY VALIDFROM) AS NextVALIDTO
FROM PMCCONTRACT
;

CREATE TEMP TABLE BASED ON SELECT DISTINCT ON 3 COLUMNS BUT WITH 1 EXTRA COLUMN

I need to make a temporary file with in it:
Partcode, MutationDate, MovementType, Qty
Every partcode has multiple mutationdates per Movementtype (there are max 9 movementtypes possible)
I need to get the last mutationdate per movementtype per partcode and the quantity that goes with that.
An example with partcode 003307
003307 2018-05-31 1 -100
003307 2018-06-11 2 -33
003307 2018-04-25 3 +25
and so on for all 9 movementtypes.
What did I get so far:
create table #LMUT(
MutationDate T_Date
,PartCode T_Code_Part
,CumInvQty T_Quantum_Qty10_3
,MovementType T_Type_PMOverInvt
)
insert #LMUT(
MutationDate,
Partcode,
CumInvQty,
MovementType)
SELECT
cast (max(MOV.MutationDate) as date)
,MOV.PartCode
,INV.MutationQty
,INV.PMOverInvtType
FROM dbo.T_PartMovementMain as MOV
inner join dbo.T_PartMovementOverInvt as INV on
INV.PMMainCode=MOV.PMMainCode
WHERE
MOV.PartMovementType = 1
group by MOV.PartCode,INV.PMOverInvtType,INV.MutationQty,MOV.MutationDate
SELECT * FROM #LMUT where partcode='003007'
drop table #LMUT
results in:
2016-12-06 00:00:00.000 003007 -24.000 2
2016-09-29 00:00:00.000 003007 -24.000 2
2016-11-09 00:00:00.000 003007 -24.000 2
2016-11-22 00:00:00.000 003007 -24.000 2
2016-10-26 00:00:00.000 003007 -24.000 2
2016-09-12 00:00:00.000 003007 -42.000 2
2016-10-13 00:00:00.000 003007 -24.000 2
2016-12-03 00:00:00.000 003007 100.000 5
2017-01-12 00:00:00.000 003007 -48.000 2
2016-10-04 00:00:00.000 003007 306.000 7
Not what I need, still have 8 times type 2
What else have I tried:
SELECT distinct MOV.Partcode,INV.PMOverInvtType,mov.MutationDate
FROM dbo.T_PartMovementMain as MOV
inner join dbo.T_PartMovementOverInvt as INV on
INV.PMMainCode=MOV.PMMainCode
WHERE
mov.MutationDate = (SELECT MAX (c.MutationDate) FROM
dbo.T_PartMovementMain as c
inner join dbo.T_PartMovementOverInvt as d on D.PMMainCode=c.PMMainCode
WHERE
C.PartMovementType = 1 AND
C.PartCode=mov.PartCode AND
D.PMMainCode = C.PMMainCode AND
D.PMOverInvtType=inv.PMOverInvtType
)
and MOV.PartMovementType = 1 and mov.partcode='003007'
order by MOV.Partcode,INV.PMOverInvtType
Results in:
3007 2 2017-01-12 00:00:00.000
3007 5 2016-12-03 00:00:00.000
3007 7 2016-10-04 00:00:00.000
That is what I want but I need to get the Qty too.
use row_number() window function
with cte as
( SELECT MOV.*,INV.*,
row_number() over(partition by INV.PMOverInvtType order by MOV.MutationDate desc)rn
FROM dbo.T_PartMovementMain as MOV
inner join dbo.T_PartMovementOverInvt as INV on
INV.PMMainCode=MOV.PMMainCode
) select cte.* from cte where rn=1
Solved it like this:
create table #LMUT(
PartCode T_Code_Part
,MovementType T_Type_PMOverInvt
,MutationDate T_Date
,CumInvQty T_Quantum_Qty10_3
)
insert #LMUT(Partcode,MovementType,MutationDate,CumInvQty)
select Artikel,Type,Datum,Aant
from (
SELECT MOV.Partcode as Artikel,INV.PMOverInvtType as Type,mov.MutationDate as Datum,INV.MutationQty as Aant,
row_number() over(partition by MOV.Partcode,INV.PMOverInvtType order by MOV.Partcode,INV.PMOverInvtType,MOV.MutationDate desc) rn
FROM dbo.T_PartMovementMain as MOV
inner join dbo.T_PartMovementOverInvt as INV on INV.PMMainCode=MOV.PMMainCode) cse
where rn=1
select * from #LMUT order by Partcode
drop table #LMUT

Select distinct records based on max(date) or NULL date

I am trying to get a list of employees based on their employee status or their most recent termination date. If the employee is active, the termination date will be NULL. There are also employees that have worked in multiple companies within our organization, I only want the record from the most recent company, whether active or terminated. An employee may also have different Employee numbers in the different companies, so the selection will have to be based on the SSN (Fica) number.
Here is an original data set:
company employee Fica First_name emp_status Term_date
5 7026 Jason T1 2013-09-16 00:00:00.000
500 7026 Jason T1 2010-11-30 00:00:00.000
7 7026 Jason T1 2009-07-31 00:00:00.000
2 90908 Jason A1 NULL
505 293866 William T1 2008-05-23 00:00:00.000
7 7243 Ashley T1 2010-07-11 00:00:00.000
2 90478 Michael T1 2013-01-11 00:00:00.000
500 90478 Michael T1 2011-09-26 00:00:00.000
500 311002 Andreas A1 NULL
3 365463 Matthew A1 NULL
500 248766 Chris T1 2007-04-23 00:00:00.000
500 90692 Kaitlyn T1 2012-03-13 00:00:00.000
2 90692 Kaitlyn A5 NULL
500 90236 Jeff T1 2011-09-26 00:00:00.000
2 90236 Jeff A1 NULL
2 90433 Nathan T1 2012-03-26 00:00:00.000
500 90433 Nathan T1 2011-09-26 00:00:00.000
Here are the results I am trying to get:
company employee Fica First_name emp_status Term_date
2 90908 Jason A1 NULL
505 293866 William T1 2008-05-23 00:00:00.000
7 7243 Ashley T1 2010-07-11 00:00:00.000
2 90478 Michael T1 2013-01-11 00:00:00.000
500 311002 Andreas A1 NULL
3 365463 Matthew A1 NULL
500 248766 Chris T1 2007-04-23 00:00:00.000
2 90692 Kaitlyn A5 NULL
2 90236 Jeff A1 NULL
2 90433 Nathan T1 2012-03-26 00:00:00.000
Thanks for any help you are able to give. I need to run this on a SQL2005 server which will be connecting to an Oracle server via ODBC.
If the dates were all populated, you could do this with a "standard" not exists query. The NULLs introduce a problem, but that problem can be solved using coalesce():
select t.*
from table t
where not exists (select 1
from table t2
where t2.employee = t.employee and
coalesce(t2.term_date, '9999-01-01') > coalesce(t.term_date, '9999-01-01)
);
NOTE: If you need for this to work on Oracle, then you need a different format for the date constant.
EDIT:
Another way to solve this uses row_number():
select t.*
from (select t.*,
row_number() over (partition by employee
order by (case when term_date is null then 0 else 1 end),
term_date desc
) as seqnum
from table t
) t
where seqnum = 1;
The rule for choosing the "last" row are embedded in the order by clause. Put the NULL value first, followed by the term_date in descending order.