how to use unique value to stop data from replicating? - sql

I have this excel document and I import the sheet from that file into my database after that I use this code to put them in separate tables:
insert into LP_Pending_Info(Service_order,Company,Country , HQ_AgingBase_Date ,PENDING_DAYS, Posting_Date,Service_Type,Service_TypeText,SUB_SVC_Type,Status,Status_Text,Reason,Reason_Text,Reason_Aging,SVC_Comment,ASC_Code,ASC_Name,ASC_JobNo,Model,CIC_Product,SerialNo,IN_OUT_WTY,IMEI,Defect_DESC,Detail_Type,Detail_TypeText,Repair_RCV_DT,Repair_RCV_TM,Complete_DT,SVC_Level,Consumer,Consumer_Text,TelNumber,City1,Street,Engineer_Code)
select Service_order,Company,Country , [HQ aging base date] ,PENDING_DAYS, Posting_Date,Service_Type,SERVICE_TYPE_TXT,SUB_SVC_Type,Status,Status_Text,Reason,Reason_Text,Reason_Aging,SVC_Comment,[ASC code],[ASC
name],ASC_JOB_NO,Model,CIC_PRD,SERIAL_NO,INOUTWTY,IMEI,Defect_DESC,Detail_Type,DETAIL_TYPE_TEXT,Repair_RCV_DT,Repair_RCV_TM,Complete_DT,SVC_Level,Consumer,consumer_txt,TEL_NUMBER,City1,Street,[Engineer code]
from LP_Pending_Jobs;
insert into LP_Part_Codes(Service_order, PartCode,serPluspart)
select Service_order, Part_code , CONVERT(nvarchar(150), Service_order)+Part_code
from LP_Pending_Jobs
cross apply (
--unpivot
select Part_code1 as Part_code where len(Part_code1) > 0
union all
select Part_code2 where len(Part_code2) > 0
union all
select Part_code3 where len(Part_code3) > 0
union all
select Part_code4 where len(Part_code4) > 0
union all
select Part_code5 where len(Part_code5) > 0
) unp;
insert into LP_PS_Codes(Service_Order, PS)
select Service_order,PS
from LP_Pending_Jobs
cross apply (
select PS1 as PS where len(PS1)>0
union all
select PS2 where len(PS2) > 0
union all
select PS3 where len(PS3) > 0
union all
select PS4 where len(PS4) > 0
union all
select PS5 where len(PS5) > 0
) unp;
insert into LP_Confirmation_Codes(Service_Order, SO_NO)
select Service_order,SO
from LP_Pending_Jobs
cross apply (
select confirmation_No1 as SO where len(confirmation_No1)>0
union all
select SO_NO2 where len(SO_NO2) > 0
union all
select SO_NO3 where len(SO_NO3) > 0
union all
select SO_NO4 where len(SO_NO4) > 0
union all
select SO_NO5 where len(SO_NO5) > 0
) unp;
----------------
insert into LP_QTY(Service_Order, QTY)
select Service_order,QTY
from LP_Pending_Jobs
cross apply (
select QTY1 as QTY where len(QTY1)>0
union all
select QTY2 where len(QTY2) > 0
union all
select QTY3 where len(QTY3) > 0
union all
select QTY4 where len(QTY4) > 0
union all
select QTY5 where len(QTY5) > 0
) unp;
insert into LP_ASC_PO_Codes(Service_Order, ASC_PO_NO)
select Service_order,ASC_PO
from LP_Pending_Jobs
cross apply (
select ASC_PO_No1 as ASC_PO where len(ASC_PO_No1)>0
union all
select ASC_PO_No2 where len(ASC_PO_No2) > 0
union all
select ASC_PO_No3 where len(ASC_PO_No3) > 0
union all
select ASC_PO_No4 where len(ASC_PO_No4) > 0
union all
select ASC_PO_No5 where len(ASC_PO_No5) > 0
) unp;
insert into LP_PO_Date(Service_Order, PO_Date)
select Service_order,PO_Date
from LP_Pending_Jobs
cross apply (
select PO_DATE1 as PO_Date where len(PO_DATE1)>0
union all
select PO_DATE2 where len(PO_DATE2) > 0
union all
select PO_DATE3 where len(PO_DATE3) > 0
union all
select PO_DATE4 where len(PO_DATE4) > 0
union all
select PO_DATE5 where len(PO_DATE5) > 0
) unp;
insert into LP_SO_Date(Service_Order, SO_Date)
select Service_order,SO_Date
from LP_Pending_Jobs
cross apply (
select SO_DATE1 as SO_Date where len(SO_DATE1)>0
union all
select SO_DATE2 where len(SO_DATE2) > 0
union all
select SO_DATE3 where len(SO_DATE3) > 0
union all
select SO_DATE4 where len(SO_DATE4) > 0
union all
select SO_DATE5 where len(SO_DATE5) > 0
) unp;
and because the data's are in one row I used cross apply to put each data in separate column.
The problem start when I join them , cause they show way more data that it should be.
here is the select code:
select distinct LP_Pending_Info.Service_Order,LP_Pending_Info.Pending_Days,
LP_Pending_Info.Service_Type,LP_Pending_Info.ASC_Code,LP_Pending_Info.Model,
LP_Pending_Info.IN_OUT_WTY, LP_Part_Codes.PartCode,LP_PS_Codes.PS,
LP_Confirmation_Codes.SO_NO,LP_Pending_Info.Engineer_Code,serPluspart
from LP_Pending_Info
inner join LP_Part_Codes on LP_Pending_Info.Service_order = LP_Part_Codes.Service_order
inner join LP_PS_Codes on LP_Part_Codes.Service_Order = LP_PS_Codes.Service_Order
inner join LP_Confirmation_Codes on LP_PS_Codes.Service_Order = LP_Confirmation_Codes.Service_Order
order by LP_Pending_Info.Service_order;
I asked around and I come to this point that I need a unique column, so I added
'serPluspart'
this column to my table in hope that it'll fix my problem but when I use my select I still see the extra data.
here is the first 25 record:
for every service order at top I have five part code, by looking at the picture the part code '4182134076' should have 2 rows because it has two part code but it shows that service order for 8 times and I don't know how to fix it. appreciate any suggestion.
the excel input file for this '4182134076' service order:
Service_order PENDING_DAYS SERVICE_TYPE ASC code MODEL INOUTWTY Part_code1 PS1 ASC_PO_No1 confirmation_No1 QTY1 PO_DATE1 SO_DATE1 Part_code2 PS2 ASC_PO_No2 SO_NO2 QTY2 PO_DATE2 SO_DATE2 Part_code3 PS3 ASC_PO_No3 SO_NO3 QTY3 PO_DATE3 SO_DATE3 Part_code4 PS4 ASC_PO_No4 SO_NO4 QTY4 PO_DATE4 SO_DATE4 Part_code5 PS5 ASC_PO_No5 SO_NO5 QTY5 PO_DATE5 SO_DATE5 Engineer code
4182134076 36 CI 4285818 SM-A310FZDDTHR LP GH96-09938A P 4182134076/1 1000237676 1 09.07.2016 GH81-13601A U 4182134076 1000224921 1 05.06.2016 7086002211

Looking at the output, you would expect eight rows because you have three pairs of binary alternatives (PartCode - GH81-13601A or GH96-09938A; PS - P or U; SO_NO 1000224921 OR 1000237676). Because PartCode, PS, and SO_NO come from three different tables and the only inner join is on the service_order, you will get 2^3 rows. Without seeing the data, it is hard to say exactly what is wrong, but I assume when you say you are only expecting two rows, that these three elements are linked, although the tables are not. I suspect you need some foreign keys, but without some sample data, I cannot be sure.
OK having seen the input data I know what to do! In LP_Part_Codes get rid of your column serPluspart (it is not helping). Now add a SubOrder (smallint) to each of LP_Part_Codes, LP_PS_Codes and LP_Confirmation_Codes.
Next add a column to your unpivots e.g:
insert into LP_PS_Codes(Service_Order, PS, SubOrder)
select Service_order,PS,SubOrder
from LP_Pending_Jobs
cross apply (
select PS1 as PS, 1 AS SubOrder where len(PS1)>0
union all
select PS2, 2 AS SubOrder where len(PS2) > 0
union all
select PS3, 3 AS SubOrder where len(PS3) > 0
union all
select PS4, 4 AS SubOrder where len(PS4) > 0
union all
select PS5, 5 AS SubOrder where len(PS5) > 0
) unp;
Do the same for LP_Part_Codes and LP_Confirmation_Codes.
Now you can amend your main select by adding LP_Part_Codes.SubOrder = LP_PS_Codes.SubOrder = LP_Confirmation_Codes.SubOrder
And you will now have only two records for this order.
HTH
Jonathan

Related

How to add rows to a specific number multiple times in the same query

I already asked for help on a part of my problem here.
I used to get 10 rows no matter if there are filled or not. But now I'm facing something else where I need to do it multiple times in the same query result.
WITH NUMBERS AS
(
SELECT 1 rowNumber
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
UNION ALL
SELECT 7
UNION ALL
SELECT 8
UNION ALL
SELECT 9
UNION ALL
SELECT 10
)
SELECT DISTINCT sp.SLC_ID, c.rowNumber, c.PCE_ID
FROM SELECT_PART sp
LEFT JOIN (
SELECT b.*
FROM NUMBERS
LEFT OUTER JOIN (
SELECT a.*
FROM (
SELECT SELECT_PART.SLC_ID, ROW_NUMBER() OVER (ORDER BY SELECT_PART.SLC_ID) as
rowNumber, SELECT_PART.PCE_ID
FROM SELECT_PART
WHERE SELECT_PART.SLC_ID = (must be the same as sp.SLC_ID and can''t hardcode it)
) a
) b
ON b.rowNumber = NUMBERS.rowNumber
) c ON c.SLC_ID = sp.SLC_ID
ORDER BY sp.SLC_ID, c.rowNumber
It works fine for the first 10 lines, but next SLC_ID only got 1 empty line
I need it to be like that
SLC_ID rowNumer PCE_ID
1 1 0001
1 2 0002
1 3 NULL
1 ... ...
1 10 NULL
2 1 0011
2 2 0012
2 3 0013
2 ... ...
2 10 0020
3 1 0021
3 ... ...
Really need it that way to build a report.
Instead of manually building a query-specific number list where you have to include every possible number you need (1 through 10 in this case), create a numbers table.
DECLARE #UpperBound INT = 1000000;
;WITH cteN(Number) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1
FROM sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
)
SELECT [Number] INTO dbo.Numbers
FROM cteN WHERE [Number] <= #UpperBound;
CREATE UNIQUE CLUSTERED INDEX CIX_Number ON dbo.Numbers([Number])
WITH
(
FILLFACTOR = 100, -- in the event server default has been changed
DATA_COMPRESSION = ROW -- if Enterprise & table large enough to matter
);
Source: mssqltips
Alternatively, since you can't add data, use a table that already exists in SQL Server.
WITH NUMBERS AS
(
SELECT DISTINCT Number as rowNumber FROM master..spt_values where type = 'P'
)
SELECT DISTINCT sp.SLC_ID, c.rowNumber, c.PCE_ID
FROM SELECT_PART sp
LEFT JOIN (
SELECT b.*
FROM NUMBERS
LEFT OUTER JOIN (
SELECT a.*
FROM(
SELECT SELECT_PART.SLC_ID, ROW_NUMBER() OVER (ORDER BY SELECT_PART.SLC_ID) as
rowNumber, SELECT_PART.PCE_ID
FROM SELECT_PART
WHERE SELECT_PART.SLC_ID = (must be the same as sp.SLC_ID and can''t hardcode it)
) a
) b
ON b.rowNumber = NUMBERS.rowNumber
) c ON c.SLC_ID = sp.SLC_ID
ORDER BY sp.SLC_ID, c.rowNumber
NOTE: Max value for this solution is 2047

Select rows based on condition on group

I have a following table, with values of code can be from 1 to 10. I want to select the product only if it has value of code greater than or equals to 3 & it should not have code = 9 assigned.
ProductId Code
844558 3
844558 3.5
844558 4
296013 2
296013 3
494948 3.5
494948 4
494948 9
392991 4
392991 9.5
Result will have only Product Id 844558 & 392991.
296013 is not selected because it has code 2 assigned
494948 is not selected because it has code 9
I wrote below query to select records with code greater than or equals 3. How to exclude products with code = 9
Declare #Product Table(ProductId INT, Code DECIMAL(10,2))
INSERT INTO #Product(ProductId, Code)
Select 844558,3
UNION
Select 844558,3.5
UNION
Select 844558,4
UNION
Select 296013,2
UNION
Select 296013,3
UNION
Select 494948,3.5
UNION
Select 494948,4
UNION
Select 494948,9
UNION
Select 392991,4
UNION
Select 392991,9.5
SELECT ProductId
FROM #Product
WHERE Code <> 9
GROUP BY ProductId
HAVING MIN(Code) >= 3
Enhance your having clause:
SELECT ProductId
FROM #Product
GROUP BY ProductId
HAVING MIN(Code) >= 3 AND
SUM(CASE WHEN Code = 9 THEN 1 ELSE 0 END) = 0
Exclude the product at source and this should return the correct result set. I have done this using a where clause which selects all of the productid values where code is 9. That way the outer result set is all codes greater than 3 and the inner result set excludes anything that has a code of 9.
Declare #Product Table(ProductId INT, Code DECIMAL(10,2))
INSERT INTO #Product(ProductId, Code)
Select 844558,3
UNION
Select 844558,3.5
UNION
Select 844558,4
UNION
Select 296013,2
UNION
Select 296013,3
UNION
Select 494948,3.5
UNION
Select 494948,4
UNION
Select 494948,9
UNION
Select 392991,4
UNION
Select 392991,9.5
SELECT ProductId
FROM #Product
WHERE ProductID not in (select ProductID from #product where Code=9)
GROUP BY ProductId
HAVING MIN(Code) >= 3;

Get every combination of sort order and value of a csv

If I have a string with numbers separated by commas, like this:
Declare #string varchar(20) = '123,456,789'
And would like to return every possible combination + sort order of the values by doing this:
Select Combination FROM dbo.GetAllCombinations(#string)
Which would in result return this:
123
456
789
123,456
456,123
123,789
789,123
456,789
789,456
123,456,789
123,789,456
456,789,123
456,123,789
789,456,123
789,123,456
As you can see not only is every combination returned, but also each combination+sort order as well. The example shows only 3 values separated by commas, but should parse any amount--Recursive.
The logic needed would be somewhere in the realm of using a WITH CUBE statement, but the problem with using WITH CUBE (in a table structure instead of CSV of course), is that it won't shuffle the order of the values 123,456 456,123 etc., and will only provide each combination, which is only half of the battle.
Currently I have no idea what to try. If someone can provide some assistance it would be appreciated.
I use a User Defined Table-valued Function called split_delimiter that takes 2 values: the #delimited_string and the #delimiter_type.
CREATE FUNCTION [dbo].[split_delimiter](#delimited_string VARCHAR(8000), #delimiter_type CHAR(1))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,cte100(num) AS
(
SELECT 1
FROM cte10 t1, cte10 t2
)
,cte10000(num) AS
(
SELECT 1
FROM cte100 t1, cte100 t2
)
,cte1(num) AS
(
SELECT TOP (ISNULL(DATALENGTH(#delimited_string),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
,cte2(num) AS
(
SELECT 1
UNION ALL
SELECT t.num+1
FROM cte1 t
WHERE SUBSTRING(#delimited_string,t.num,1) = #delimiter_type
)
,cte3(num,[len]) AS
(
SELECT t.num
,ISNULL(NULLIF(CHARINDEX(#delimiter_type,#delimited_string,t.num),0)-t.num,8000)
FROM cte2 t
)
SELECT delimited_item_num = ROW_NUMBER() OVER(ORDER BY t.num)
,delimited_value = SUBSTRING(#delimited_string, t.num, t.[len])
FROM cte3 t;
Using that I was able to parse the CSV to a table and join it back to itself multiple times and use WITH ROLLUP to get the permutations you are looking for.
WITH Numbers as
(
SELECT delimited_value
FROM dbo.split_delimiter('123,456,789',',')
)
SELECT CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR)
FROM Numbers as Nums1
LEFT JOIN Numbers as Nums2
ON Nums2.delimited_value not in (Nums1.delimited_value)
LEFT JOIN Numbers as Nums3
ON Nums3.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value)
LEFT JOIN Numbers as Nums4
ON Nums4.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value, Nums3.delimited_value)
GROUP BY CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR) WITH ROLLUP
If you will potentially have more than 3 or 4, you'll want to expand your code accordingly.

SQL order by included character and string

I have a table and i want to colum joint_no column. The column's values are like these
FW-1
FW-2
.
.
.
FW-13
FW-R1
FW-1A
When i ordered them i get this results
FW-1
FW-10
FW-11
FW-12
FW-13
FW-1A
.
.
FW-R1
I want to get this result after sql query
FW-1
FW-1A
FW-2
FW-3
..
FW-13
FW-R1
can anybody help me?
If you can do it, I'd advise you to renumber the values so that the 'logical' order sticks to the alphabetical order. F-1 will then be updated to F-01, or F-001.
If you cannot do it, add a field that will be populated with the 'ordered' form of your code. You 'll then be able to order by the F-001 column and still display the F-1 value
Otherwise ordering your records will rapidly become your nightmare.
Using Patindex to find the first numeric expression as first sort field, then extracting the numeric part as integer as second sortfield and using the whole string as third sort field you might get the desired result.
Declare #a Table (c varchar(50))
Insert Into #a
Select 'FW-1'
Union Select 'FW-10'
Union Select 'FW-11'
Union Select 'FW-12'
Union Select 'FW-13'
Union Select 'FW-1A'
Union Select 'FW-2'
Union Select 'FW-3'
Union Select 'FW-R1'
Union Select 'FW-A1'
;With CTE as
(Select 1 as ID
Union All
Select ID + 1 from CTE where ID < 100
)
Select * from
(
Select c
,PATINDEX('%[0-9]%',c) as s1
,(Select Cast(
(Select Case
When SUBSTRING(c, ID, 1) LIKE '[0-9]'
Then SUBSTRING(c, ID, 1)
Else ''
End
From (Select * from CTE) AS X(ID)
Where ID <= LEN(c)
For XML PATH(''))
as int)
)
as s2
from
#a
) x
order by
s1,s2,c
With the output:
FW-1 4 1 -1
FW-1A 4 1 -1A
FW-2 4 2 -2
FW-3 4 3 -3
FW-10 4 10 -10
FW-11 4 11 -11
FW-12 4 12 -12
FW-13 4 13 -13
FW-A1 5 1 A1
FW-R1 5 1 R1
If the leading part is not fixed (FW-) you might need to add one additional sort field
Declare #a Table (c varchar(50))
Insert Into #a
Select 'FW-1'
Union Select 'FW-10'
Union Select 'FW-11'
Union Select 'FW-12'
Union Select 'FW-13'
Union Select 'FW-1A'
Union Select 'FW-2'
Union Select 'FW-3'
Union Select 'FW-R1'
Union Select 'FW-A1'
Union Select 'AB-A1'
Union Select 'AB-11'
;With CTE as
(Select 1 as ID
Union All
Select ID + 1 from CTE where ID < 100
)
Select * from
(
Select c
,SubString(c,1,PATINDEX('%[0-9]%',c)-1) as S0
,PATINDEX('%[0-9]%',c) as s1
,(Select Cast(
(Select Case
When SUBSTRING(c, ID, 1) LIKE '[0-9]'
Then SUBSTRING(c, ID, 1)
Else ''
End
From (Select * from CTE) AS X(ID)
Where ID <= LEN(c)
For XML PATH(''))
as int)
)
as s2
from
#a
) x
order by
s0,s1,s2,c

SQL Running Subtraction

I have a result set as below:
Item ExpectedQty ReceivedQty Short
Item01 30 45 5
Item01 20 45 5
Item02 40 38 2
item03 50 90 10
item03 30 90 10
item03 20 90 10
query is:
select a.Item, a.ExpectedQty,b.ReceivedQty, b.Short
from a join b on a.Item = b.Item
I need to get result as in second chart. Basically I have a total of received quantity in each line and I need to show received quantity against Expected Quantity, if there is any shortage I need to show in last line.
Expected:
Item ExpectedQty ReceivedQty Short
item01 30 30 0
item01 20 15 5
item02 40 38 2
item03 50 50 0
item03 30 30 0
item03 20 10 10
Thanks in advance.
Edited,
Vession 02 ;
-- Just a brief of business scenario is table has been created for a good receipt.
-- So here we have good expected line with PurchaseOrder(PO) in first few line.
-- And then we receive each expected line physically and that time these
-- quantity may be different
-- due to business case like quantity may damage and short quantity like that.
-- So we maintain a status for that eg: OK, Damage, also we have to calculate
-- short quantity
-- based on total of expected quantity of each item and total of received line.
if object_id('DEV..Temp','U') is not null
drop table Temp
CREATE TABLE Temp
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
Item VARCHAR(32),
PO VARCHAR(32) NULL,
ExpectedQty INT NULL,
ReceivedQty INT NULL,
[STATUS] VARCHAR(32) NULL,
BoxName VARCHAR(32) NULL
)
-- Please see first few line with PO data will be the expected lines,
-- and then rest line will be received line
INSERT INTO TEMP (Item,PO,ExpectedQty,ReceivedQty,[STATUS],BoxName)
SELECT 'ITEM01','PO-01','30',NULL,NULL,NULL UNION ALL
SELECT 'ITEM01','PO-02','20',NULL,NULL,NULL UNION ALL
SELECT 'ITEM02','PO-01','40',NULL,NULL,NULL UNION ALL
SELECT 'ITEM03','PO-01','50',NULL,NULL,NULL UNION ALL
SELECT 'ITEM03','PO-02','30',NULL,NULL,NULL UNION ALL
SELECT 'ITEM03','PO-03','20',NULL,NULL,NULL UNION ALL
SELECT 'ITEM04','PO-01','30',NULL,NULL,NULL UNION ALL
SELECT 'ITEM01',NULL,NULL,'20','OK','box01' UNION ALL
SELECT 'ITEM01',NULL,NULL,'25','OK','box02' UNION ALL
SELECT 'ITEM01',NULL,NULL,'5','DAMAGE','box03' UNION ALL
SELECT 'ITEM02',NULL,NULL,'38','OK','box04' UNION ALL
SELECT 'ITEM02',NULL,NULL,'2','DAMAGE','box05' UNION ALL
SELECT 'ITEM03',NULL,NULL,'30','OK','box06' UNION ALL
SELECT 'ITEM03',NULL,NULL,'30','OK','box07' UNION ALL
SELECT 'ITEM03',NULL,NULL,'30','OK','box08' UNION ALL
SELECT 'ITEM03',NULL,NULL,'10','DAMAGE','box09' UNION ALL
SELECT 'ITEM04',NULL,NULL,'25','OK','box10'
-- Below Table is my expected result based on above data.
-- I need to show those data following way.
-- So I appreciate if you can give me an appropriate query for it.
-- Note: first row is blank and it is actually my table header. :)
SELECT ''as'ITEM', ''as'PO#', ''as'ExpectedQty',''as'ReceivedQty',
''as'DamageQty' ,''as'ShortQty' UNION ALL
SELECT 'ITEM01','PO-01','30','30','0' ,'0' UNION ALL
SELECT 'ITEM01','PO-02','20','15','5' ,'0' UNION ALL
SELECT 'ITEM02','PO-01','40','38','2' ,'0' UNION ALL
SELECT 'ITEM03','PO-01','50','50','0' ,'0' UNION ALL
SELECT 'ITEM03','PO-02','30','30','0' ,'0' UNION ALL
SELECT 'ITEM03','PO-03','20','10','10','0' UNION ALL
SELECT 'ITEM04','PO-01','30','25','0' ,'5'
One part of the problem is to get the running totals of expected item qunatities. For that you'd need a way to distinguish rows with same items from each other and a rule for the order of discharging same item quantities.
For the purpose of my attempt at solving your problem I'm going to assume there's a timestamp column whose values provide the order of discharge and are unique within same item groups.
Here's the sample data definition I was testing my solution on:
CREATE TABLE TableA (Item varchar(50), ExpectedQty int, Timestamp int);
INSERT INTO TableA
SELECT 'Item01', 30, 1 UNION ALL
SELECT 'Item01', 20, 2 UNION ALL
SELECT 'Item02', 40, 1 UNION ALL
SELECT 'item03', 50, 1 UNION ALL
SELECT 'item03', 30, 2 UNION ALL
SELECT 'item03', 20, 3;
CREATE TABLE TableB (Item varchar(50), ReceivedQty int);
INSERT INTO TableB
SELECT 'Item01', 45 UNION ALL
SELECT 'Item02', 38 UNION ALL
SELECT 'item03', 90;
And here's my solution:
SELECT
Item,
ExpectedQty,
ReceivedQty = CASE
WHEN RemainderQty >= 0 THEN ExpectedQty
WHEN RemainderQty < -ExpectedQty THEN 0
ELSE RemainderQty + ExpectedQty
END,
Short = CASE
WHEN RemainderQty >= 0 THEN 0
WHEN RemainderQty < -ExpectedQty THEN ExpectedQty
ELSE ABS(RemainderQty)
END
FROM (
SELECT
a.Item,
a.ExpectedQty,
RemainderQty = b.ReceivedQty - a.RunningTotalQty
FROM (
SELECT
a.Item,
a.Timestamp,
a.ExpectedQty,
RunningTotalQty = SUM(a2.ExpectedQty)
FROM TableA a
INNER JOIN TableA a AS a2 ON a.Item = a2.Item AND a.Timestamp >= a2.Timestamp
GROUP BY
a.Item,
a.Timestamp,
a.ExpectedQty
) a
INNER JOIN TableB b ON a.Item = b.Item
) s
select a.Item, a.ExpectedQty,b.ReceivedQty, (a.ExpectedQty - b.ReceivedQty) as 'Short' from a join b on a.Item = b.Item
SELECT a.ExpectedQty,
b.ReceivedQty,
CASE WHEN b.ReceivedQty < a.ExpectedQty
THEN b.ReceivedQty - a.ExpectedQty
ELSE 0
END Short
FROM dbo.a a
INNER JOIN dbo.b b
ON a.ItemId = b.ItemId