create a row index column beginning at -1 - sql

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

Related

Create interval from discrete dates

I have a function which saves the current status of several objects and writes it in a table, which looks like something like this:
ObjectId StatusId Date
1 10 2020-04-04 00:00:00.000
2 10 2020-04-04 00:00:00.000
1 11 2020-04-05 00:00:00.000
2 10 2020-04-05 00:00:00.000
1 10 2020-04-06 00:00:00.000
2 10 2020-04-06 00:00:00.000
I would like to make it an interval grouped by ObjectId and StatusId.
So for the above the preferred output would look like this:
ObjectId StatusId StartDate EndDate
1 10 2020-04-04 00:00:00.000 2020-04-04 00:00:00.000
1 11 2020-04-05 00:00:00.000 2020-04-05 00:00:00.000
1 10 2020-04-06 00:00:00.000 2020-04-06 00:00:00.000
2 10 2020-04-04 00:00:00.000 2020-04-06 00:00:00.000
Note one object can have the same status on multiple occasions but if it had a different status it needs to be in a separate interval. So simple group by and max(Date) doesn't work in my case.
Thanks in advance.
This is a form of gaps-and-islands. For this purpose, the difference of row numbers is probably the simplest method:
select objectid, status, min(date), max(date)
from (select t.*,
row_number() over (partition by objectid order by date) as seqnum,
row_number() over (partition by objectid, status order by date) as seqnum_2
from t
) t
group by objectid, status, (seqnum - seqnum_2);
Why this works can be a little cumbersome to explain. However, if you look at the results of the subquery, you will see how the difference is constant for the groups you want to identify.

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
;

Select Max() and Min() date and Sum up quantity

I have table with data as below
StartDate EndDate ID Qty
2017-09-01 2017-10-01 PJFC1000205 1
2017-10-01 2017-11-01 PJFC1000205 2
2017-11-01 2017-12-01 PJFC1000205 3
2017-12-01 2018-01-01 PJFC1000205 4
I wish sum up the qty and wish the output as below
StartDate EndDate ID Qty
2017-09-01 2018-01-01 PJFC1000205 10
Is it possible to do so? How I can do it?
I'm using MSSQL 2014.
Please guide me, thanks.
Using the group by on ID and aggregate functions on the other fields should do the trick.
SELECT min(Start_Date), max(End_Date), ID, sum(Qty)
FROM table
GROUP BY ID;

Subtracting from different rows

I am trying to subtract the startdate from the enddate on different rows, but only for the same code.
For example:
I want to do startdate in row 2 for C002 (2012-07-01) minus enddate in row 1 for C002 (2012-06-30).
The result should be 1 (day) for row 2. No data should be in row 1.
Row 4 should show 1 (day) as well.
How can I go about doing this?
row code startdate enddate
1 C002 2011-07-01 00:00:00.000 2012-06-30 00:00:00.000
2 C002 2012-07-01 00:00:00.000 2013-06-30 00:00:00.000
3 C003 2011-07-01 00:00:00.000 2012-06-30 00:00:00.000
4 C003 2012-07-01 00:00:00.000 2013-06-30 00:00:00.000
select max(row),code,datediff(day,max(startdate),min(enddate)) as ouputtt
from table
group by
code
Try this-
Select x.code, y.startdate-x.enddate
From table1 x left outer join table1 y on
X.code=Y.code
Where
X.enddate<y.startdate
You could use this query, which adds the requested value as an additional column:
select row, code, startdate, enddate,
datediff('d', lag(enddate) over (partition by code order by row1), startdate) df
from mytable

SQL Server : reset Id and recreate data

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)