Sql Query Compare and Sum - sql

I have these problem I need to match the sum a columns to see if they match with the Final Total of the Invoice by Invoice Number ( I am working in a query to do it)
Example
Invoice No Line _no Total Line Invoice total Field I will create
----------------------------------------------------------------------
45 1 145 300 145
45 2 165 300 300 Match
46 1 200 200 200 Match
47 1 100 300 100
47 2 100 300 200
47 3 100 300 300 Match

You want a cumulative sum. In SQL Server 2012+, just do:
select e.*,
(case when InvoiceTotal = sum(InvoiceTotal) over (partition by invoice_no order by line_no)
then 'Match'
end)
from example e;
In earlier versions of SQL Server, I would be inclined to do it with a correlated subquery:
select e.*
(case when InvoiceTotal = (select sum(InvoiceTotal)
from example e2
where e2.Invoice_no = e.invoice_no and
e2.line_no >= e.line_no
)
then 'Match'
end)
from example e;
You can also do this with a cross apply as M Ali suggests.
EDIT:
Now that I think about the problem, you don't need a cumulative sum. That was just how I originally thought of the problem. So, this will work in SQL Server 2008:
select e.*,
(case when InvoiceTotal = sum(InvoiceTotal) over (partition by invoice_no)
then 'Match'
end)
from example e;
You can't get the cumulative sum out (the second to last column) without more manipulation, but the match column is not hard.

SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE TEST(InvoiceNo INT, Line_no INT, TotalLine INT, InvoiceTotal INT)
INSERT INTO TEST VALUES
(45 ,1 ,145 ,300),
(45 ,2 ,165 ,300),
(46 ,1 ,200 ,200),
(47 ,1 ,100 ,300),
(47 ,2 ,100 ,300),
(47 ,3 ,100 ,300)
Query 1:
SELECT t.[InvoiceNo]
,t.[Line_no]
,t.[TotalLine]
,t.[InvoiceTotal]
,C.Grand_Total
,CASE WHEN C.Grand_Total = t.[InvoiceTotal]
THEN 'Match' ELSE '' END AS [Matched]
FROM TEST t
CROSS APPLY (SELECT SUM([TotalLine]) AS Grand_Total
FROM TEST
WHERE [InvoiceNo] = t.[InvoiceNo]
AND [Line_no] < = t.[Line_no]) C
Results:
| INVOICENO | LINE_NO | TOTALLINE | INVOICETOTAL | GRAND_TOTAL | MATCHED |
|-----------|---------|-----------|--------------|-------------|---------|
| 45 | 1 | 145 | 300 | 145 | |
| 45 | 2 | 165 | 300 | 310 | |
| 46 | 1 | 200 | 200 | 200 | Match |
| 47 | 1 | 100 | 300 | 100 | |
| 47 | 2 | 100 | 300 | 200 | |
| 47 | 3 | 100 | 300 | 300 | Match |

Is this what you're looking for? I think subquery is what you're asking about, but i'm guessing to get an end result similar to the entire thing.
select t."Invoice No", t."Line no_", t."Invoice total",
calcTotals.lineNum as calcSum, case when t."Invoice total" = calcTotals.lineNum then 'matched' else 'not matched' end
from [table] t
inner join (
select "Invoice No" as invoiceNumber,
sum("Line _no") as lineNum
from [table]
group by "Invoice No"
) calcTotals on t."Invoice No" = calcTotals.invoiceNumber

Related

SQL logic to determine unsold inventory and corresponding available dates (Available to sell)

I am looking for advice on how to generate SQL to be used in SQL Server that will show available inventory to sell and the corresponding date that said inventory will be available. I am easily able to determine if we have inventory that is available immediately but can't wrap my head around what logic would be needed to determine future available quantities.
In the below table. The +/- column represents the weekly inbound vs outbound and the quantity available is a rolling SUM OVER PARTITION BY of the +/- column. I was able to get the immediate quantity available through this simple logic:
Case when Min(X.Qty_Available) > 0 Then Min(X.Qty_Available) else 0 END
AS Immediate_available_Qty
Table:
+-------------+---------------+---------------+------+---------------+
| Item Number | Item Name | week_end_date | +/- | Qty_Available |
+-------------+---------------+---------------+------+---------------+
| 123456 | Fidget Widget | 7/13/2019 | 117 | 117 |
| 123456 | Fidget Widget | 7/20/2019 | 49 | 166 |
| 123456 | Fidget Widget | 7/27/2019 | -7 | 159 |
| 123456 | Fidget Widget | 8/3/2019 | -12 | 147 |
| 123456 | Fidget Widget | 8/10/2019 | -1 | 146 |
| 123456 | Fidget Widget | 8/17/2019 | 45 | 191 |
| 123456 | Fidget Widget | 8/24/2019 | -1 | 190 |
| 123456 | Fidget Widget | 8/31/2019 | -1 | 189 |
| 123456 | Fidget Widget | 9/7/2019 | 50 | 239 |
+-------------+---------------+---------------+------+---------------+
My desired results of this query would be as follows:
+-----------+-----+
| Output | Qty |
+-----------+-----+
| 7/13/2019 | 117 |
| 7/20/2019 | 29 |
| 8/17/2019 | 43 |
+-----------+-----+
the second availability is determined by taking the first available quantity of 117 out of each line in Qty_Available column and finding the new minimum. If the new min is Zero, find the next continuously positive string of data (that runs all the way to the end of the data). Repeat for the third_available quantity and then stop.
I was on the thought train of pursuing RCTE logic but don't want to dive into that rabbit hole if there is a better way to tackle this issue and I'm not even sure the RCTE work for this problem?
This should return your expected result:
SELECT Item_Number, Min(week_end_date), Sum("+/-")
FROM
(
SELECT *
-- put a positive value plus all following negative values in the same group
-- using a Cumulative Sum over 0/1
,Sum(CASE WHEN "+/-" > 0 THEN 1 ELSE 0 end)
Over (PARTITION BY Item_Number
ORDER BY week_end_date
ROWS UNBOUNDED PRECEDING) AS grp
FROM my_table
) AS dt
WHERE grp <= 3 -- only the 1st 3 groups
GROUP BY Item_Number, grp
So here's what I came up with. I know this is poor, I didn't want to leave this thread high and dry and maybe I can get more insight on a better path. Please know that I've never had any real training so I don't know what I don't know.
I ended up running this into a temp table and altering the commented out section in table "A". then re-running that into a temp table.
Select
F.Upc,
F.name,
F.Week_end_date as First_Available_Date,
E.Qty_Available_1
From
(
Select Distinct
D.Upc,
D.name,
Case When Min(D.Rolling_Qty_Available) Over ( PARTITION BY D.upc) < 1 then 0 else
Min(D.Rolling_Qty_Available) Over ( PARTITION BY D.upc) END as Qty_Available_1,
Case When Max(D.Look_up_Ref) Over ( PARTITION BY D.upc) = 0 then '-1000' else
Max(D.Look_up_Ref) Over ( PARTITION BY D.upc) END as Look_up_Ref_1
From
(
Select
A.Upc,
A.name,
A.Week_end_Date,
A.Rolling_Qty_Available,
CASE WHEN
C.Max_Row = A.Row_num and A.[Rolling_Qty_Available] >1 THEN 1
ELSE
CASE WHEN
Sum(A.Calc_Row_Thing) OVER (Partition by A.UPC Order by A.Row_Num DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND Current ROW
) = (C.Max_Row - A.Row_num + 1)
THEN
C.Max_Row - A.Row_num + 1
ELSE 0 END
END as Look_up_Ref
FROM (
Select
G.Upc,
G.Name,
G.Week_End_Date,
G.Row_num,
G.Calc_Row_Thing,
G.Rolling_Qty_Available
--CASE When (G.Rolling_Qty_Available -
--isnull(H.Qty_Available_1,0)) > 0 then 1 else - 0 END as
--Calc_Row_Thing,
From [dbo].[ATS_item_detail_USA_vw] as G
--Left Join [dbo].[tmp_ats_usa_qty_1] as H on G.upc = H.upc
) AS A --Need to subtract QTY 1 out of here and below
join (
SELECT
B.upc,
Max(Row_num) AS Max_Row
FROM [dbo].[ATS_item_detail_USA_vw] AS B
GROUP BY B.upc
) as C on A.upc = C.upc
) as D
GROUP BY
D.Upc,
D.name,
D.Rolling_Qty_Available,
D.Look_up_Ref
HAVING Max(D.Look_up_Ref) > 1
) as E
Left join
(
SELECT
A.Upc,
A.name,
A.Week_end_Date,
A.Rolling_Qty_Available,
CASE WHEN
C.Max_Row = A.Row_num and A.[Rolling_Qty_Available] >1 THEN 1
ELSE
CASE WHEN
Sum(A.Calc_Row_Thing) OVER (Partition by A.UPC Order by A.Row_Num DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND Current ROW
) = (C.Max_Row - A.Row_num + 1)
THEN
C.Max_Row - A.Row_num + 1
ELSE 0 END
END as Look_up_Ref
From (
Select
G.Upc,
G.Name,
G.Week_End_Date,
G.Row_num,
G.Calc_Row_Thing,
G.Rolling_Qty_Available
--CASE When (G.Rolling_Qty_Available -
--isnull(H.Qty_Available_1,0)) > 0 then 1 else - 0 END as
--Calc_Row_Thing,
From [dbo].[ATS_item_detail_USA_vw] as G
--Left Join [dbo].[tmp_ats_usa_qty_1] as H on G.upc = H.upc
) as A --subtract qty_1 out the start qty 2 calc
join (
SELECT
B.upc,
Max(Row_num) as Max_Row
FROM [dbo].[ATS_item_detail_USA_vw] as B
GROUP BY B.upc
) AS C ON A.upc = C.upc
) AS F ON E.upc = F.upc and E.Look_up_Ref_1 = F.Look_up_Ref

How to fetch records from complex database?

I need to fetch multiple records and single records at a time with multiple tables from MSSQL. Tables from where I need to collect data is like below :
1. tblExpenseType :
--> ExpenseTypeId | ExpenseTypeName
--> 1 | OVERTIME EXP.
--> 2 | REPAIRING EXP.
--> 3 | LU EXP.
2. tblMemoDetails :
--> MemoID | MemoNumber | FkTruckId
--> 1011 | 1 | 5
--> 1012 | 2 | 6
--> 1013 | 3 | 5
--> 1014 | 4 | 7
3. tblMemoExpense :
--> FkMemoNumber | FkExpenseTypeId | Amount
--> 1 | 1 | 150
--> 1 | 3 | 225
--> 2 | 1 | 50
--> 2 | 2 | 100
--> 2 | 3 | 150
4. tblMemoTrips :
--> FkTripId | FkMemoNumber | TripAmount
--> 11 | 1 | 1000
--> 9 | 2 | 500
--> 3 | 2 | 100
--> 4 | 2 | 2000
I'm trying to fetch data using below logic but it's making me confusing:
with MemoList
As
(select
_jpMemo.MemoId as memoId
from TMS_JPMemo _jpMemo
where _jpMemo.FkTruckId = 5)
select
ML.memoId
--,ME.FkExpenseTypeId
,ME.Amount
,ET.ExpenseTypeName
from TMS_MemoExpense ME
join MemoList ML on ML.memoId = ME.FkMemoId
join TMS_ExpenseTypes ET on ET.ExpenseTypeId = ME.FkExpenseTypeId
I need result like if I select FkTruckId 5 then it will show me below result.
I need results like below for FkTruckId 5 :
MemoNumber | TripDetails | TripAmount | OVERTIME | REPAIRING | LU
1 | 11 | 1000 | 150 | -- | 225
| Total | 1000 | 150 | -- | 225
And If I select FkTruckId 6 then it would show me a result like :
MemoNumber | TripDetails | TripAmount | OVERTIME | REPAIRING | LU
2 | 9 | 500 | -- | -- | --
| 3 | 100 | -- | -- | --
| 4 | 2000 | 50 | 100 | 150
| Total | 2600 | 50 | 100 | 150
So it's making me confusing how to solve this and how to achieve this type of complex data from tables.
You are displaying two different things per memo:
the memo's trips with their trip amount
the memo's expenses
Apart from belonging to the same memo, the two are not related, i.e. there are no expenses per trip. So it's actually two different things you want to show. Make this two separate queries. You can glue them together with UNION ALL, as you obviously want them both in one query result. Something like:
with memo as
(
select memoid
from tblmemodetails
where fktruckid = 5
)
select memonumber, tripid, tripamount, overtime, repairing, lu
from
(
-- -------------------------------------------------------------------------------
-- The memos' trips. They have a trip amount but no further expenses of their own.
select
fkmemonumber as memonumber,
fktripid as tripid,
tripamount,
null as overtime,
null as repairing,
null as lu,
1 sortkey
from tblmemotrips
where fkmemonumber in (select memonumber from memo)
group by fkmemonumber, fktripid -- one row per memo and trip
-- -------------------------------------------------------------------------------
union all
-- -------------------------------------------------------------------------------
-- The memos' expenses. They are not reated to particular trips.
select
fkmemonumber as memonumber,
null as tripid,
null as tripamount,
sum(case when fkexpensetypeid = 1 then amount end) as overtime,
sum(case when fkexpensetypeid = 2 then amount end) as repairing,
sum(case when fkexpensetypeid = 3 then amount end) as lu,
2 as sortkey
from tblmemoexpense
where fkmemonumber in (select memonumber from memo)
group by fkmemonumber -- one row per memo
-- -------------------------------------------------------------------------------
) data
order by memonumber, sortkey;
You could use a series of JOINs to put the tables in relation, and then conditional aggregation to pivot the data. This implies that the number of columns to pivot is fixed (if more values are added to table tblExpenseType, the query would need to be adapted) :
SELECT
md.MemoNumber,
mt.FkTripId AS TripDetails,
mt.TripAmount,
MAX(CASE WHEN et.ExpenseTypeName = 'OVERTIME EXP.' THEN me.amount END) AS OVERTIME,
MAX(CASE WHEN et.ExpenseTypeName = 'REPARINING EXP.' THEN me.amount END) AS REPARING,
MAX(CASE WHEN et.ExpenseTypeName = 'LU EXP.' THEN me.amount END) AS LU
FROM
tblMemoDetails AS md
LEFT JOIN tblMemoExpense AS me ON me.FkMemoNumber = md.MemoNumber
LEFT JOIN tblMemoTrips AS mt ON mt.FkMemoNumber = md.MemoNumber
LEFT JOIN tblExpenseType AS et ON et.ExpenseTypeId = me.FkExpenseTypeId
GROUP BY
md.MemoNumber,
mt.FkTripId AS TripDetails,
mt.TripAmount
Conditional aggregation is the way to go. I think the query looks a little more like this:
SELECT md.TruckId, md.MemoNumber,
COALESCE(mt.FkTripId, 'Total') AS TripDetails, mt.TripAmount,
SUM(CASE WHEN et.ExpenseTypeName = 'OVERTIME EXP.' THEN me.amount ELSE 0 END) AS OVERTIME,
SUM(CASE WHEN et.ExpenseTypeName = 'REPARINING EXP.' THEN me.amount ELSE 0 END) AS REPARING,
SUM(CASE WHEN et.ExpenseTypeName = 'LU EXP.' THEN me.amount ELSE 0 END) AS LU
FROM tblMemoDetails md LEFT JOIN
tblMemoExpense me
ON me.FkMemoNumber = md.MemoNumber LEFT JOIN
tblMemoTrips mt
ON mt.FkMemoNumber = md.MemoNumber LEFT JOIN
tblExpenseType et
ON et.ExpenseTypeId = me.FkExpenseTypeId
WHERE md.TruckId = #TruckId
GROUP BY GROUPING SETS ( (md.TruckId, md.MemoNumber, mt.FkTripId, mt.TripAmount), () );
The GROUPING SETS generates the total.

ORDER BY or GROUP BY based on three columns in SQL Server

I have a table like this..
Priority | Amount | Case
P1 | 100 | 1
P1 | 200 | 2
P1 | 300 | 1
P3 | 400 | 3
I want to first order this by Priority and Amount (Descending) and then Case, to look like this.
Priority | Amount | Case
P1 | 300 | 1
P1 | 100 | 1
P1 | 200 | 2
P3 | 400 | 3
If I use ORDER BY Priority, Amount DESC, Case then it returns this. Where Case is not grouped together based on the highest Amount value.
Priority | Amount | Case
P1 | 300 | 1
P1 | 200 | 2
P1 | 100 | 1
P3 | 400 | 3
EDIT: Adding one more record for clarity:
Priority | Amount | Case
P1 | 100 | 1
P1 | 200 | 2
P1 | 300 | 1
P1 | 200 | 0 << New record
P3 | 400 | 3
This should return as:
Priority | Amount | Case
P1 | 300 | 1
P1 | 100 | 1
P1 | 200 | 0
P1 | 200 | 2
P3 | 400 | 3
where first it grouped by Priority, amongst that sorted by highest Amount and then within the Amount grouped by Case
You need to use a windowed aggregate to find the highest amount within each Case, and then use that for sorting:
declare #t table ([Priority] varchar(19) not null,Amount int not null, [Case] int not null)
insert into #t ([Priority],Amount,[Case]) values
('P1',100,1),
('P1',200,2),
('P1',300,1),
('P1',200,0),
('P3',400,3)
select
*
from
(
select *,MAX(Amount) OVER (PARTITION BY [Case]) as mAmount
from #t
) t
order by [Priority],mAmount desc,[Case],Amount desc
Result:
Priority Amount Case mAmount
------------------- ----------- ----------- -----------
P1 300 1 300
P1 100 1 300
P1 200 0 200
P1 200 2 200
P3 400 3 400
Also, please consider renaming some of your columns - I've had to wrap two in [] brackets because they're reserved words. It's usually better to just avoid reserved words completely.
CREATE TABLE SHANKATABLE (PRIORITY VARCHAR(2), AMOUNT INT, [CASE] INT)
INSERT INTO SHANKATABLE VALUES('P1', 100 , 1)
INSERT INTO SHANKATABLE VALUES ('P1', 200 , 2)
INSERT INTO SHANKATABLE VALUES ('P1', 300 , 1)
INSERT INTO SHANKATABLE VALUES ('P3', 400 , 3)
To achieve first result simply use below query,
Based on Damien_The_Unbeliever answer I am just updating my answer.
SELECT PRIORITY,[CASE],AMOUNT
FROM (
SELECT PRIORITY,[CASE],AMOUNT,MAX(Amount) OVER(PARTITION BY [Case]) AS mAmount
FROM SHANKATABLE
) Temp
ORDER BY
[Priority],mAmount DESC,[Case],Amount DESC
updated sql fiddle demo
I think you want this
select * from tablename ORDER BY Priority, [case] , Amount DESC
The identifier cannot be a reserved keyword in SQL, cannot have embedded spaces, and must not include supplementary characters.
An identifier that doesn’t comply with these rules must be delimited.
For example, an attribute called 2006 is considered an irregular identifier because it starts with a digit, and therefore must be delimited as "2006" or [2006]. A regular identifier such as y2006 can be referenced without delimiters simply as y2006, or it can be optional with delimiters. You might prefer not to delimit regular identifiers because the delimiters tend to clutter the code.
try this:-
select [PRIORITY],[amount],[case] from Table
order by [PRIORITY], [CASE] asc,AMOUNT desc

SQL Server Multiple Groupings

I am stumped by what seems like a simple problem.
We have the following Table.
ID--- ---Income--- ---Years Offset--- ---Income By Offset---
1 1000 1 NULL
2 500 1 NULL
3 400 1 NULL
4 0 1 NULL
5 2000 2 NULL
6 0 2 NULL
7 400 2 NULL
What I would love to figure out how to do is to sum all of the income column by the "Years Offset column" and place in the first row of the "Income by Offset column." What would be awesome is if the Income by Offset column has values of 1900 in row 1 and 2400 in row 5 with the rest of them rows being untouched.
I know that this sound like a simple problem. But I have tried Window functions, Row_number(), SELF joining tables and a piece of it is solved with each but am having trouble putting it all together.
Thanks in advance,
George
My Version of Your Table
DECLARE #yourTable TABLE (ID INT,Income INT,[Years Offset] INT,[Income By Offset] INT NULL);
INSERT INTO #yourTable
VALUES (1,1000,1,NULL),
(2,500,1,NULL),
(3,400,1,NULL),
(4,0,1,NULL),
(5,2000,2,NULL),
(6,0,2,NULL),
(7,400,2,NULL);
Actual Query
SELECT ID,
Income,
[Years Offset],
CASE
WHEN ID = MIN(ID) OVER (PARTITION BY [Years Offset])
THEN SUM(Income) OVER (PARTITION BY [Years Offset])
ELSE [Income By Offset]
END AS [Income By Offset]
FROM #yourTable
Results
ID Income Years Offset Income By Offset
----------- ----------- ------------ ----------------
1 1000 1 1900
2 500 1 NULL
3 400 1 NULL
4 0 1 NULL
5 2000 2 2400
6 0 2 NULL
7 400 2 NULL
This should return the required result set:
SELECT ID, Income, [Years Offset],
CASE WHEN ROW_NUMBER() OVER (PARTITION By [Years Offset]
ORDER BY ID) = 1
THEN SUM(Income) OVER (PARTITION BY [Years Offset])
ELSE NULL
END AS [Income By Offset]
FROM mytable
Windowed version of SUM calculates the Income per [Years Offset]. ROW_NUMBER() is used to return this value only for the first row of each [Years Offset] group.
Demo here
How about:
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Income
(
ID INT PRIMARY KEY,
Income INT NOT NULL,
YearsOffset Int NOT NULL,
IncomeByOffset INT NULL
)
INSERT INTO Income (ID, Income, YearsOffset)
VALUES (1,1000,1),
(2,500,1),
(3,400,1),
(4,0,1),
(5, 2000, 2),
(6,0,2),
(7,400,2)
Query 1:
UPDATE Income
SET IncomeByOffset = I.IncomeByOffset
From
(
SELECT YearsOffset, SUM(Income) As IncomeByOffset, Min(ID) As MinId
FROM Income
GROUP BY YearsOffset
) I
WHERE Income.YearsOffset = I.YearsOffset
AND Income.Id = I.MinId
Results:
Query 2:
SELECT *
FROM Income;
Results:
| ID | Income | YearsOffset | IncomeByOffset |
|----|--------|-------------|----------------|
| 1 | 1000 | 1 | 1900 |
| 2 | 500 | 1 | (null) |
| 3 | 400 | 1 | (null) |
| 4 | 0 | 1 | (null) |
| 5 | 2000 | 2 | 2400 |
| 6 | 0 | 2 | (null) |
| 7 | 400 | 2 | (null) |

Alternate of lead lag function in SQL Server 2008

I want to compare the current row with a value in the next row. SQL has LEAD and LAG functions to get the next and previous values but I can not use them because I am using SQL Server 2008.
So how do I get this?
I have table with output
+----+-------+-----------+-------------------------+
| Id | ActId | StatusId | MinStartTime |
+----+-------+-----------+-------------------------+
| 1 | 42 | 1 | 2014-02-14 11:17:21.203 |
| 2 | 42 | 1 | 2014-02-14 11:50:19.367 |
| 3 | 42 | 1 | 2014-02-14 11:50:19.380 |
| 4 | 42 | 6 | 2014-02-17 05:25:57.280 |
| 5 | 42 | 6 | 2014-02-19 06:09:33.150 |
| 6 | 42 | 1 | 2014-02-19 06:11:24.393 |
| 7 | 42 | 6 | 2014-02-19 06:11:24.410 |
| 8 | 42 | 8 | 2014-02-19 06:44:47.070 |
+----+-------+-----------+-------------------------+
What I want to do is if the current row status is 1 and the next row status is 6 and both times are the same (up to minutes) then I want to get the row where the status is 1.
Eg: Id 6 row has status 1 and Id 7 row has status 6 but both times are the same ie. 2014-02-19 06:11
So I want to get this row or id for status 1 ie. id 6
In your case, the ids appear to be numeric, you can just do a self-join:
select t.*
from table t join
table tnext
on t.id = tnext.id - 1 and
t.StatusId = 1 and
tnext.StatusId = 6 and
datediff(second, t.MinStartTime, tnext.MinStartTime) < 60;
This isn't quite the same minute. It is within 60 seconds. Do you actually need the same calendar time minute? If so, you can do:
select t.*
from table t join
table tnext
on t.id = tnext.id - 1 and
t.StatusId = 1 and
tnext.StatusId = 6 and
datediff(second, t.MinStartTime, tnext.MinStartTime) < 60 and
datepart(minute, t.MinStartTime) = datepart(minute, tnext.MinStartTime);
Just posting a more complex join using two different tables created with Gordon's foundation. Excuse the specific object names, but you'll get the gist. Gets the percentage change in samples from one to the next.
SELECT
fm0.SAMPLE curFMSample
, fm1.SAMPLE nextFMSample
, fm0.TEMPERATURE curFMTemp
, fm1.TEMPERATURE nextFMTemp
, ABS(CAST((fm0.Temperature - fm1.Temperature) AS DECIMAL(4, 0)) / CAST(fm0.TEMPERATURE AS DECIMAL(4, 0))) AS fmTempChange
, fm0.GAUGE curFMGauge
, fm1.GAUGE nextFMGauge
, ABS(CAST((fm0.GAUGE - fm1.GAUGE) AS DECIMAL(4, 4)) / CAST(fm0.GAUGE AS DECIMAL(4, 4))) AS fmGaugeChange
, fm0.WIDTH curFMWidth
, fm1.WIDTH nextFMWidth
, ABS(CAST((fm0.Width - fm1.Width) AS DECIMAL(4, 2)) / CAST(fm0.Width AS DECIMAL(4, 2))) AS fmWidthChange
, cl0.TEMPERATURE curClrTemp
, cl1.TEMPERATURE nextClrTemp
, ABS(CAST((cl0.Temperature - cl1.Temperature) AS DECIMAL(4, 0)) / CAST(cl0.TEMPERATURE AS DECIMAL(4, 0))) AS clrTempChange
FROM
dbo.COIL_FINISHING_MILL_EXIT_STR02 fm0
INNER JOIN dbo.COIL_FINISHING_MILL_EXIT_STR02 fm1 ON (fm0.SAMPLE = fm1.SAMPLE - 1 AND fm1.coil = fm0.coil)
INNER JOIN dbo.COIL_COILER_STR02 cl0 ON fm0.coil = cl0.coil AND fm0.SAMPLE = cl0.SAMPLE
INNER JOIN dbo.COIL_COILER_STR02 cl1 ON (cl0.SAMPLE = cl1.SAMPLE - 1 AND cl1.coil = cl0.coil)
WHERE
fm0.coil = 2015515872
Well, I would suggest a very simple solution if you do not have a sequential row id but a different step (if some records were deleted for example..):
declare #t table(id int, obj_name varchar(5))
insert #t select 1,'a'
insert #t select 5,'b'
insert #t select 22,'c'
insert #t select 543,'d'
---------------------------------
select *from #t
Example Source Table #t:
---------------------------------
id obj_name
1 a
5 b
22 c
543 d
---------------------------------
Select with self join
select obj_name_prev=tt.obj_name, obj_name_next=min(t.obj_name)
from #t t
join #t tt on tt.id < t.id
group by tt.obj_name
Result:
---------------------------------
obj_name_prev obj_name_next
a b
b c
c d
---------------------------------