SQL : updating a column based on other columns - sql-server

SQL Server:
I have a following table.
ID Type1 Type2 error
_____________________
1 P107 0057 NULL
2 P101 1142 NULL
3 P107 1142 NULL
now here I have to check type1 column in table 1 if data exists, type2 in table2.
Lets assume that P101 exists in table1 and 0057 exist in table2.
Table1 have many columns but we are checking for col = 'type1' same is true for table2 just checking col = 'type2'.
So, error generated should be like:
ID Type1 Type2 error
_____________________
1 P107 0057 <type1 invalid>
2 P101 1142 <type2 invalid>
3 P107 1142 <type1 invalid> + <type2 invalid>
PS: There might be other messages that are already existing in error column, we dont want to delete those messages but to add the new messages if any.
For example I might have the table like :
ID Type1 Type2 error
_____________________
1 P107 0057 NULL
2 P101 1142 <duplicate>
3 P107 1142 NULL
now, I want to add the new error in id = 2 like,
ID Type1 Type2 error
_____________________
1 P107 0057 <type1 invalid>
2 P101 1142 <duplicate> + <type2 invalid>
3 P107 1142 <type1 invalid> + <type2 invalid>
Any help will be appreciated !! Thanks in advance .

If the following produces the results you want:
SELECT t.ID, t.Type1, t.Type2,
error = COALESCE(t.error + ' + ', '') + CASE
WHEN t1.type1 IS NULL AND t2.type2 IS NULL
THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.type1 IS NULL THEN '<type1 invalid>'
WHEN t2.type2 IS NULL THEN '<type2 invalid>'
ELSE t.error END
FROM dbo.table AS t
LEFT OUTER JOIN dbo.Table1 AS t1
ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2
ON t.Type2 = t2.Type2
WHERE t1.Type1 IS NULL OR t2.Type2 IS NULL;
Then you can run this update statement:
UPDATE t
SET error = COALESCE(t.error + ' + ', '') + CASE
WHEN t1.type1 IS NULL AND t2.type2 IS NULL
THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.type1 IS NULL THEN '<type1 invalid>'
WHEN t2.type2 IS NULL THEN '<type2 invalid>'
ELSE t.error END
FROM dbo.table AS t
LEFT OUTER JOIN dbo.Table1 AS t1
ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2
ON t.Type2 = t2.Type2
WHERE t1.Type1 IS NULL OR t2.Type2 IS NULL;
Added where clause to account for new information added to the question as an afterthought. Assuming that the column is NULL when there isn't yet an error message.
EDIT updated for yet MORE new requirements.
EDIT and again. Is there an echo?
Here's a repro you can run in tempdb to see that, no, you don't need to use variables and no, you don't need to write 10! (yes, I know what factorial means) case expressions to get this done.
Core table:
USE tempdb;
GO
CREATE TABLE dbo.[table]
(
ID INT,
Type1 VARCHAR(4),
Type2 VARCHAR(4),
Type3 VARCHAR(4),
Type4 VARCHAR(4),
Type5 VARCHAR(4),
Type6 VARCHAR(4),
Type7 VARCHAR(4),
Type8 VARCHAR(4),
Type9 VARCHAR(4),
Type10 VARCHAR(4),
error VARCHAR(MAX)
);
GO
Some rows:
INSERT dbo.[table] SELECT -- this will yield type 1 invalid:
1,'P107','0057','x', 'x','x','x','x', 'x','x','x',NULL
UNION ALL SELECT -- this will yield type 2 invalid:
2,'P101','1142','x', 'x','x','x','x', 'x','x','x','<duplicate>'
UNION ALL SELECT -- this will yield type 1 + type 2 invalid:
3,'P107','1142','x', 'x','x','x','x', 'x','x','x',NULL
UNION ALL SELECT -- no problems here:
4,'x', 'x', 'x205','x','x','x','y676','x','x','x',NULL
UNION ALL SELECT -- this will yield type 3 invalid:
5,'x', 'x', 'x206','x','x','x','y676','x','x','x','<other>';
Related tables and rows:
CREATE TABLE dbo.Table1 (Type1 VARCHAR(4));
CREATE TABLE dbo.Table2 (Type2 VARCHAR(4));
CREATE TABLE dbo.Table3 (Type3 VARCHAR(4));
CREATE TABLE dbo.Table4 (Type4 VARCHAR(4));
CREATE TABLE dbo.Table5 (Type5 VARCHAR(4));
CREATE TABLE dbo.Table6 (Type6 VARCHAR(4));
CREATE TABLE dbo.Table7 (Type7 VARCHAR(4));
CREATE TABLE dbo.Table8 (Type8 VARCHAR(4));
CREATE TABLE dbo.Table9 (Type9 VARCHAR(4));
CREATE TABLE dbo.Table10(Type10 VARCHAR(4));
INSERT dbo.Table1 SELECT 'P101';
INSERT dbo.Table2 SELECT '0057';
INSERT dbo.Table3 SELECT 'x205';
INSERT dbo.Table7 SELECT 'y676';
-- I know you won't have x's but I assume you'll have
-- valid data most of the time.
INSERT dbo.Table1 SELECT 'x';
INSERT dbo.Table2 SELECT 'x';
INSERT dbo.Table3 SELECT 'x';
INSERT dbo.Table4 SELECT 'x';
INSERT dbo.Table5 SELECT 'x';
INSERT dbo.Table6 SELECT 'x';
INSERT dbo.Table7 SELECT 'x';
INSERT dbo.Table8 SELECT 'x';
INSERT dbo.Table9 SELECT 'x';
INSERT dbo.Table10 SELECT 'x';
Let's make sure the table looks right:
SELECT * FROM dbo.[table];
Now, a single statement, only 10 case expressions, not 10!:
UPDATE t SET error = REPLACE(COALESCE(t.error, '')
+ CASE WHEN t1.type1 IS NULL THEN '<type1 invalid>' ELSE '' END
+ CASE WHEN t2.type2 IS NULL THEN '<type2 invalid>' ELSE '' END
+ CASE WHEN t3.type3 IS NULL THEN '<type3 invalid>' ELSE '' END
+ CASE WHEN t4.type4 IS NULL THEN '<type4 invalid>' ELSE '' END
+ CASE WHEN t5.type5 IS NULL THEN '<type5 invalid>' ELSE '' END
+ CASE WHEN t6.type6 IS NULL THEN '<type6 invalid>' ELSE '' END
+ CASE WHEN t7.type7 IS NULL THEN '<type7 invalid>' ELSE '' END
+ CASE WHEN t8.type8 IS NULL THEN '<type8 invalid>' ELSE '' END
+ CASE WHEN t9.type9 IS NULL THEN '<type9 invalid>' ELSE '' END
+ CASE WHEN t10.type10 IS NULL THEN '<type10 invalid>' ELSE '' END, '><', '> + <')
FROM dbo.[table] AS t
LEFT OUTER JOIN dbo.Table1 AS t1 ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2 ON t.Type2 = t2.Type2
LEFT OUTER JOIN dbo.Table3 AS t3 ON t.Type3 = t3.Type3
LEFT OUTER JOIN dbo.Table4 AS t4 ON t.Type4 = t4.Type4
LEFT OUTER JOIN dbo.Table5 AS t5 ON t.Type5 = t5.Type5
LEFT OUTER JOIN dbo.Table6 AS t6 ON t.Type6 = t6.Type6
LEFT OUTER JOIN dbo.Table7 AS t7 ON t.Type7 = t7.Type7
LEFT OUTER JOIN dbo.Table8 AS t8 ON t.Type8 = t8.Type8
LEFT OUTER JOIN dbo.Table9 AS t9 ON t.Type9 = t9.Type9
LEFT OUTER JOIN dbo.Table10 AS t10 ON t.Type10 = t10.Type10
WHERE t1.Type1 IS NULL
OR t2.Type2 IS NULL
OR t3.Type3 IS NULL
OR t4.Type4 IS NULL
OR t5.Type5 IS NULL
OR t6.Type6 IS NULL
OR t7.Type7 IS NULL
OR t8.Type8 IS NULL
OR t9.Type9 IS NULL
OR t10.Type10 IS NULL;
GO
Once the update has run, let's check and make sure the right rows have been updated:
SELECT * FROM dbo.[table];
GO
And cleanup:
DROP TABLE dbo.[table],
dbo.Table1, dbo.Table2, dbo.Table3, dbo.Table4, dbo.Table5,
dbo.Table6, dbo.Table7, dbo.Table8, dbo.Table9, dbo.Table10;

UPDATE yt
SET error = CASE WHEN t1.Type1 IS NULL AND t2.Type2 IS NULL THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.Type1 IS NULL THEN '<type1 invalid>'
WHEN t2.Type2 IS NULL THEN '<type2 invalid>'
END
FROM YourTable yt
LEFT JOIN table1 t1
ON yt.Type1 = t1.Type1
LEFT JOIN table2 t2
ON yt.Type2 = t2.Type2
WHERE t1.Type1 IS NULL
OR t2.Type2 IS NULL;

Related

SQL 2005: Optimize upsert-like Stored Procedure using Cursor, possible?

Ok So this is the second time i'm trying to fix this.
I was wondering if there is a possible way to optimize the cursor created for a stored procedure, used to iterate through a big select statement with two unions. In which later on, the stored procedure begins inserting values to a staging table checking each value against a "where not exist" select statement.
Or better yet, is it possible to create all this with a select statement and possibly joins.
The inserting process takes far too long to complete, and I would recon selecting the data would be much faster.
Here is an example of the SQL:
declare #ID1 varchar(40) ,
#ID2 varchar(20) ,
#State varchar(20) ,
#isActive bit
Declare CuTable SCROLL INSENSITIVE cursor for
Select
Cast(ID1 as Varchar(20)) AS ID1,
Cast(ID2 as Varchar(20)) AS ID2,
'AT' AS [State],
CASE When (isAvtiveDate > { fn CURDATE() }) or isAvtiveDate is null Then 1 else 0 end AS isAvtive
From
server1.db.dbo.table1
Inner Join
server1.db.dbo.table2 on ID2 = ID1
Where ID3 = 1 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
UNION
Select
Cast(ID1 as Varchar(20)) AS ID1,
Cast(ID2 as Varchar(20)) AS ID2,
'AP' AS [State],
CASE When (isActiveDate > { fn CURDATE() }) or isActiveDate is null Then 1 else 0 end AS isActive
From
server1.db.dbo.table1
Inner Join
server1.db.dbo.table2 on ID2 = ID1
Where
ID3 = 2 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
UNION
Select
Cast(ID1 as Varchar(20)) AS ID1,
Cast(ID2 as Varchar(20)) AS ID2,
'AH' AS [State],
CASE When (isActiveDate > { fn CURDATE() }) or isActiveDate is null Then 1 else 0 end AS isActive
From server1.db.dbo.table1 inner join server1.db.dbo.table2 on ID2 = ID1
inner join server1.db.dbo.table13 on ID2 = ID4
Where ID3 = 5 and toDate is null and fromDate is not null AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
Open CuTable
Fetch Next From CuTable Into #ID1, #ID2, #[State], #isActive
While ##Fetch_Status = 0
Begin
Insert Into StagingTable (ID1, ID2, [State], isActive)
--Values
Select #ID1, #ID2, #[State], #isActive
where not exists(select * from StagingTable where ID1 = #ID1 and ID2 = #ID2)
Fetch Next From CuTable Into #ID1, #ID2, #[State], #isActive
End
close CuTable
deallocate CuTable
HEADS UP: I'm using SQL SERVER 2005
UPDATE regarding Leonidas199x comment thread:
Don't think you need a cursor at all, as the data is not dynamically changing. You should be able to do this with a set based approach. Below is an example using CTE, with a left join to only insert those that do not exist in the staging table:
;WITH CTE AS
(
SELECT CAST(ID1 as Varchar(20)) AS ID1,
CAST(ID2 as Varchar(20)) AS ID2,
'AT' AS [State],
CASE When (isAvtiveDate > { fn CURDATE() }) or isAvtiveDate is null Then 1 else 0 end AS isAvtive
FROM server1.db.dbo.table1
INNER JOIN server1.db.dbo.table2 on ID2 = ID1
WHERE ID3 = 1 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
UNION
SELECT CAST(ID1 as Varchar(20)) AS ID1,
CAST(ID2 as Varchar(20)) AS ID2,
'AP' AS [State],
CASE WHEN (isActiveDate > { fn CURDATE() }) or isActiveDate is null Then 1 else 0 end AS isActive
FROM server1.db.dbo.table1
INNER JOIN server1.db.dbo.table2 on ID2 = ID1
WHERE ID3 = 2 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
UNION
SELECT
Cast(ID1 as Varchar(20)) AS ID1,
Cast(ID2 as Varchar(20)) AS ID2,
'AH' AS [State],
CASE When (isActiveDate > { fn CURDATE() }) or isActiveDate is null Then 1 else 0 end AS isActive
FROM server1.db.dbo.table1
INNER JOIN server1.db.dbo.table2 ON ID2 = ID1
INNER JOIN server1.db.dbo.table13 ON ID2 = ID4
WHERE ID3 = 5 and toDate is null and fromDate is not null AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
)
INSERT INTO StagingTable
(
ID1,
ID2,
[State],
isActive
)
SELECT DISTINCT
CT.ID1,
CT.ID2,
CT.[State],
CT.isActive
FROM CTE AS CT
LEFT JOIN StagingTable AS ST ON ST.ID1 = CT.ID1 AND ST.ID2 = CT.ID2
WHERE ST.ID1 IS NULL
AND ST.ID2 IS NULL;
Given the requirement to check each row as the cursor does, I would use the following, using a temp table to check each set of ID1 and ID2 that are identified are unique when inserting into the temp table, then do the insert to the staging table from the temp table:
/*Create temp table*/
IF OBJECT_ID('tempdb..#tmpData') IS NOT NULL DROP TABLE #tmpData
GO
CREATE TABLE #tmpData
(
ID1 VARCHAR(20) ,
ID2 VARCHAR(20) ,
[State] VARCHAR(2) ,
IsActiveData BIT
)
/*Insert into the temp table, with each insert join back to the temp table to ensure ID1 and ID2 are not already inserted*/
INSERT INTO #tmpData
(
ID1 ,
ID2 ,
[State] ,
IsActiveData
)
SELECT CAST(ID1 as Varchar(20)) AS ID1,
CAST(ID2 as Varchar(20)) AS ID2,
'AT' AS [State],
CASE WHEN (isAvtiveDate > { fn CURDATE() }) or isAvtiveDate is null Then 1 else 0 end AS isAvtive
FROM server1.db.dbo.table1
INNER JOIN server1.db.dbo.table2 on ID2 = ID1
WHERE ID3 = 1 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
INSERT INTO #tmpData
(
ID1 ,
ID2 ,
[State] ,
IsActiveData
)
SELECT CAST(T1.ID1 as VARCHAR(20)) AS ID1,
CAST(T2.ID2 as VARCHAR(20)) AS ID2,
'AP' AS [State],
CASE WHEN (isActiveDate > { fn CURDATE() }) or isActiveDate is null Then 1 else 0 end AS isActive
FROM server1.db.dbo.table1 AS T1
INNER JOIN server1.db.dbo.table2 AS T2 ON T2.ID2 = T1.ID1
LEFT JOIN #tmpData AS T ON T.ID1 = T1.ID1 AND T.ID2 = T2.ID2
WHERE ID3 = 2 AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
AND T.ID1 IS NULL
AND T.ID2 IS NULL
INSERT INTO #tmpData
(
ID1 ,
ID2 ,
[State] ,
IsActiveData
)
SELECT
Cast(T1.ID1 as Varchar(20)) AS ID1,
Cast(T2.ID2 as Varchar(20)) AS ID2,
'AH' AS [State],
CASE When (isActiveDate > { fn CURDATE() }) OR isActiveDate IS NULL Then 1 else 0 end AS isActive
FROM server1.db.dbo.table1 AS T1
INNER JOIN server1.db.dbo.table2 AS T2 ON T2.ID2 = T1.ID1
INNER JOIN server1.db.dbo.table13 AS T13 ON T2.ID2 = T13.ID4
LEFT JOIN #tmpData AS T ON T.ID1 = T1.ID1 AND T.ID2 = T2.ID2
WHERE ID3 = 5
AND toDate IS NULL
AND fromDate IS NOT NULL
AND isActiveDate <= ISNULL(isActiveDate,'2020-01-01')
AND T.ID1 IS NULL
AND T.ID2 IS NULL
/*Insert into the staging table from the temp table ensuring only records that are not already in there are inserted.*/
INSERT INTO StagingTable
(
ID1,
ID2,
[State],
isActive
)
SELECT CT.ID1,
CT.ID2,
CT.[State],
CT.isActive
FROM #tmpData AS CT
LEFT JOIN StagingTable AS ST ON ST.ID1 = CT.ID1 AND ST.ID2 = CT.ID2
WHERE ST.ID1 IS NULL
AND ST.ID2 IS NULL;

How to execute 2 SQL statements inside a CASE

I have the following SQL query statement:
INSERT INTO #mt_API
SELECT
[dbo].fn_AddTimeZoneOffset(APHIST.ActionDate,'CET') AS ASDATE
, [dbo].fn_AddTimeZoneOffset(APHIST.ReturnDate,'CET') AS ATDATE
,API_HIST.[ActionPlanItemID]
,API_HIST.[ActionPlanID]
,PIT.[ProductItemID]
,PIT.ProductItemCode
,PIT.QRCode
,PIT.Name
,ISNULL((SELECT TOP 1 mRSP.TotalRemainingAtStore FROM #mt_RemainingStockProduct AS mRSP
WHERE mRSP.InventoryDate <= APHIST.ReturnDate
ORDER BY mRSP.InventoryDate DESC), 0) AS StoreTotalStock
,P.[Weight] AS ItemWeight
,M.UnitMeasureCode as Unit
,PIT.Quantity AS ItemQuantity
,P.ItemUnitWeight
,P.Quantity as ProductQuantity
,E1.FullName AS Emp1
,E2.FullName AS Emp2
,E3.FullName AS Emp3
,E4.FullName AS Emp4
,SECT.Name AS Sector
,CASE WHEN n=0 then 0 else [ItemStatus] end as [ItemStatus]
,APHIST.IsActionOver as ActionOver
FROM
[Sales].[ActionPlanItem_History] AS API_HIST
INNER JOIN
[Sales].[ActionPlan_History] AS APHIST On APHIST.ActionPlanID = API_HIST.ActionPlanID
INNER JOIN
[Production].[ProductItem] AS PIT ON API_HIST.ProductItemID =PIT.ProductItemID
INNER JOIN
Production.Product as P ON PIT.ProductID = P.ProductID AND PIT.ProductID = P.ProductID AND
PIT.ProductID = P.ProductID
INNER JOIN
Production.UnitMeasure as M ON M.UnitMeasureID = P.WeightUnitMeasureID
LEFT OUTER JOIN
Sales.Employee AS E1 ON APHIST.EmployeeID1 = E1.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E2 ON APHIST.EmployeeID2 = E2.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E3 ON APHIST.EmployeeID3 = E3.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E4 ON APHIST.EmployeeID4 = E4.EmployeeID
INNER JOIN
Sales.Sector AS SECT ON APHIST.SectorID = SECT.SectorID
INNER JOIN
Production.ProductSubcategory as PS on P.ProductSubcategoryID=PS.ProductSubcategoryID
INNER JOIN
Production.ProductCategory as PC on PS.ProductCategoryID= PC.ProductCategoryID
CROSS APPLY (Values(0),(1)) d(n)
WHERE P.StoreID=#StoreID
--WHERE PC.ProductCategoryID=#RootCategory AND P.StoreID=#StoreID
--ORDER BY ProductItemCode, ATDATE
ORDER BY ASDATE , ProductItemCode
SELECT
API1.ASDATE AS StartDate
,API1.ATDATE AS ReturnDate
,API1.ActionPlanItemID
,API1.ActionPlanID
,API1.ProductItemID
,API1.ProductItemCode
,API1.QRCode
,API1.Name
,API1.StoreTotalStock
,API1.ItemWeight
,API1.ItemQuantity
,API1.ItemUnitWeight
,API1.Unit
,API1.ProductQuantity
,API1.Emp1
,API1.Emp2
,API1.Emp3
,API1.Emp4
,API1.Sector
,API1.ItemStatus
,API1.ActionOver
,(API1.StoreTotalStock +
(SELECT SUM(
CASE API2.ItemStatus
WHEN 0 THEN -1
WHEN 1 THEN 1
ELSE 0
END * API2.ItemUnitWeight)
FROM #mt_API AS API2
WHERE API2.ID <= API1.ID
)
-
(
**select
case ISNULL(SUM([ProductItemWeight]), 0)
when 0 then 0
else SUM([ProductItemWeight])
end
from [ExplosiveTracking].[Production].[TransfertHistory]
where stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') < stuff(convert(varchar(20),API1.ASDATE,120),17,6,'')**
)
) AS ItemWeightBal
FROM #mt_API AS API1
Inside the CASE statement I am returning the SUM([ProductItemWeight]) if it is not NULL, but then at same time, I need to execute the following inside the same CASE :
delete from #tempTransfert
where stuff(convert(varchar(20),#tempTransfert.TransferDate,120),17,6,'') < stuff(convert(varchar(20),API1.ASDATE,120),17,6,'')
ADDED MORE TEST :
If I run what I wan to accomplish in a standalone new query as below then the DELETE and SELECT works find inside the CASE
CREATE TABLE #tempTransfert
(
[ID] uniqueidentifier,
[ProductId] int,
[SourceId] int,
TransferDate DateTime,
TotalMovedProduct DECIMAL(16,4)
)
Insert into #tempTransfert
select
[ID],[ProductId], [SourceId], stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') as TransferDate, SUM([ProductItemWeight]) as TotalMovedProduct
from [ExplosiveTracking].[Production].[TransfertHistory]
group by [ProductId],ID, [SourceId], stuff(convert(varchar(20),TransfertDateTime,120),17,6,'')
select * from #tempTransfert
MERGE #tempTransfert AS T
USING (select
case ISNULL(SUM([ProductItemWeight]) , 0)
when 0 then 0
else SUM([ProductItemWeight])
end
, ID
from [ExplosiveTracking].[Production].[TransfertHistory]
where stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') < stuff(convert(varchar(20),'2017-02-28 15:38:00',120),17,6,'')
Group by ID
) as S ([ProductItemWeight],ID)
ON (T.ID = S.ID)
WHEN MATCHED
THEN DELETE;
BUT when I added in the complete query as below , I have a SYNTAX error near MERGE reported :
DECLARE #m_StoreTotalStock AS DECIMAL(18,3)
DECLARE #mt_API AS TABLE
(
ID INT IDENTITY(1,1), ASDATE DATETIME,ATDATE DATETIME,
ActionPlanItemID INT, ActionPlanID INT,
ProductItemID INT, ProductItemCode VARCHAR(50),
QRCode VARCHAR(50), Name VARCHAR(50),
StoreTotalStock decimal(18,3), ItemWeight decimal(18,3),
Unit VARCHAR(50), ItemQuantity INT,
ItemUnitWeight DECIMAL(18,4), ProductQuantity INT,
Emp1 VARCHAR(50), Emp2 VARCHAR(50),
Emp3 VARCHAR(50), Emp4 VARCHAR(50),
Sector VARCHAR(50), ItemStatus TINYINT,ActionOver INt
)
DECLARE #mt_RemainingStockProduct AS TABLE
(
StoreID INT,InventoryDate DATETIME,ProductID INT, TotalRemainingAtStore DECIMAL(18,2)
)
CREATE TABLE #tempTransfert
(
[ID] uniqueidentifier,
[ProductId] int,
[SourceId] int,
TransferDate DateTime,
TotalMovedProduct DECIMAL(16,4)
)
Insert into #tempTransfert
select
[ID],[ProductId], [SourceId], stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') as TransferDate, SUM([ProductItemWeight]) as TotalMovedProduct
from [ExplosiveTracking].[Production].[TransfertHistory]
group by [ProductId],ID, [SourceId], stuff(convert(varchar(20),TransfertDateTime,120),17,6,'')
select * from #tempTransfert
/** Get Remaining StockBy Product **/
INSERT INTO #mt_RemainingStockProduct
(
StoreID, InventoryDate, ProductID,TotalRemainingAtStore
)
--SELECT InventoryDate, SUM(TotalRemainingAtStore) AS TotalRemainingAtStore FROM
--(
SELECT StoreID, InventoryDate, ProductID, SUM(Remaining) OVER (PARTITION BY StoreID ) AS TotalRemainingAtStore FROM
(
SELECT
P.StoreID, P.InventoryDate, P.ProductID,
--SUM(PIT.Quantity * P.ItemUnitWeight)-SUM(PIT.UsedQuantity * P.ItemUnitWeight) AS Remaining
SUM(PIT.Quantity * P.ItemUnitWeight) AS Remaining
FROM Sales.Store AS S
INNER JOIN Production.ProductItem AS PIT
INNER JOIN Production.Product AS P ON PIT.ProductID = P.ProductID
INNER JOIN Production.UnitMeasure AS UM ON P.WeightUnitMeasureID = UM.UnitMeasureID ON
S.BusinessEntityID = P.StoreID
INNER JOIN Production.Location AS LOC ON S.BusinessEntityID = LOC.StoreID AND
P.LocationID = LOC.LocationID AND P.LocationID = LOC.LocationID
WHERE (P.IsDeleted = 0) AND (PIT.IsDeleted = 0) AND P.StoreID = 4
GROUP BY P.StoreID,P.InventoryDate, P.ProductID, UM.UnitMeasureCode, S.Name, LOC.MaxQuantity
) AS RST1
--) AS RST2
--GROUP BY RST2.InventoryDate
/** Endof Get Remaining StockBy Product **/
-- Get Store total product items weight
SELECT #m_StoreTotalStock = SUM(PIW.TotalWeight)
FROM dbo.v_ProductItemWeight AS PIW
WHERE StoreID = 4
INSERT INTO #mt_API
SELECT [dbo].fn_AddTimeZoneOffset(APHIST.ActionDate,'CET') AS ASDATE
, [dbo].fn_AddTimeZoneOffset(APHIST.ReturnDate,'CET') AS ATDATE
,API_HIST.[ActionPlanItemID]
,API_HIST.[ActionPlanID]
,PIT.[ProductItemID]
,PIT.ProductItemCode
,PIT.QRCode
,PIT.Name
,ISNULL((SELECT TOP 1 mRSP.TotalRemainingAtStore FROM #mt_RemainingStockProduct AS mRSP
WHERE mRSP.InventoryDate <= APHIST.ReturnDate
ORDER BY mRSP.InventoryDate DESC), 0) AS StoreTotalStock
,P.[Weight] AS ItemWeight
,M.UnitMeasureCode as Unit
,PIT.Quantity AS ItemQuantity
,P.ItemUnitWeight
,P.Quantity as ProductQuantity
,E1.FullName AS Emp1
,E2.FullName AS Emp2
,E3.FullName AS Emp3
,E4.FullName AS Emp4
,SECT.Name AS Sector
,CASE WHEN n=0 then 0 else [ItemStatus] end as [ItemStatus]
,APHIST.IsActionOver as ActionOver
FROM
[Sales].[ActionPlanItem_History] AS API_HIST
INNER JOIN
[Sales].[ActionPlan_History] AS APHIST On APHIST.ActionPlanID = API_HIST.ActionPlanID
INNER JOIN
[Production].[ProductItem] AS PIT ON API_HIST.ProductItemID =PIT.ProductItemID
INNER JOIN
Production.Product as P ON PIT.ProductID = P.ProductID AND PIT.ProductID = P.ProductID AND
PIT.ProductID = P.ProductID
INNER JOIN
Production.UnitMeasure as M ON M.UnitMeasureID = P.WeightUnitMeasureID
LEFT OUTER JOIN
Sales.Employee AS E1 ON APHIST.EmployeeID1 = E1.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E2 ON APHIST.EmployeeID2 = E2.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E3 ON APHIST.EmployeeID3 = E3.EmployeeID
LEFT OUTER JOIN
Sales.Employee AS E4 ON APHIST.EmployeeID4 = E4.EmployeeID
INNER JOIN
Sales.Sector AS SECT ON APHIST.SectorID = SECT.SectorID
INNER JOIN
Production.ProductSubcategory as PS on P.ProductSubcategoryID=PS.ProductSubcategoryID
INNER JOIN
Production.ProductCategory as PC on PS.ProductCategoryID= PC.ProductCategoryID
CROSS APPLY (Values(0),(1)) d(n)
WHERE P.StoreID=4
--WHERE PC.ProductCategoryID=#RootCategory AND P.StoreID=#StoreID
--ORDER BY ProductItemCode, ATDATE
ORDER BY ASDATE , ProductItemCode
SELECT
API1.ASDATE AS StartDate
,API1.ATDATE AS ReturnDate
,API1.ActionPlanItemID
,API1.ActionPlanID
,API1.ProductItemID
,API1.ProductItemCode
,API1.QRCode
,API1.Name
,API1.StoreTotalStock
,API1.ItemWeight
,API1.ItemQuantity
,API1.ItemUnitWeight
,API1.Unit
,API1.ProductQuantity
,API1.Emp1
,API1.Emp2
,API1.Emp3
,API1.Emp4
,API1.Sector
,API1.ItemStatus
,API1.ActionOver
,(API1.StoreTotalStock +
(SELECT SUM(
CASE API2.ItemStatus
WHEN 0 THEN -1
WHEN 1 THEN 1
ELSE 0
END * API2.ItemUnitWeight)
FROM #mt_API AS API2
WHERE API2.ID <= API1.ID
)
-
--select
-- case ISNULL(SUM([ProductItemWeight]), 0)
-- when 0 then 0
-- else SUM([ProductItemWeight])
-- end
--from [ExplosiveTracking].[Production].[TransfertHistory]
--where stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') < stuff(convert(varchar(20),API1.ASDATE,120),17,6,'')
(
**MERGE #tempTransfert AS T
USING (select
case ISNULL(SUM([ProductItemWeight]) , 0)
when 0 then 0
else SUM([ProductItemWeight])
end
, ID
from [ExplosiveTracking].[Production].[TransfertHistory]
where stuff(convert(varchar(20),TransfertDateTime,120),17,6,'') < stuff(convert(varchar(20),API1.ASDATE,120),17,6,'')
Group by ID
) as S ([ProductItemWeight],ID)
ON (T.ID = S.ID)
WHEN MATCHED
THEN DELETE;
)**
) AS ItemWeightBal
FROM #mt_API AS API1
END
The MERGE part is suppose to first return the SUM of ItemWeight within a DateTime range, then when those records has been read, I need to delete them from #tempTransfert table otherwise, on the next loop it will read all records again
Any idea what syntax error can it be ?
Thanks for your help on this
Regards

T-SQL update join 1:N

I have two tables:
Table1:
id fee1 fee2
1 0.00 0.00
2 0.00 0.00
Table2:
id fee_no fee
1 A 10.00
1 B 20.00
2 A 80.00
2 B 90.00
SQL:
update a
set a.fee1 = isnull(a.fee1, 0)
+ (case when b.fee_no ='A'
then cast(isnull(b.fee, 0) as decimal(30, 2))
else 0 end),
a.fee2 = isnull(a.fee2, 0)
+ (case when b.fee_no ='B'
then cast(isnull(b.fee, 0) as decimal(30,2))
else 0 end)
from table1 a
inner join table2 b on a.id = b.id
After I executed this SQL, only fee1 of table1 is updated, while fee2 is not. Finally I used two SQL statements to update fee1 and fee2 respectively.
But why doesn't this SQL statement work?
Here is create table statement:
create table table1(
id int null,
fee1 dec(30,2) null,
fee2 dec(30,2) null
)
insert into table1 (id,fee1,fee2)
select 1,0,0 union
select 2,0,0
create table table2(
id int null,
fee_no varchar(10) null,
fee dec(30,2) null
)
insert into table2 (id,fee_no,fee)
select 1,'A',10 union
select 1,'B',20 union
select 2,'A',80 union
select 2,'B',90
The problem with your query is that each row of table1 is updated twice. However when the second update takes place, it operates on the original data of the table. So, fee2 is set back to 0.
To properly UPDATE you need a query like this:
update a
set a.fee1 = isnull(a.fee1, 0)
+ (case when b.fee_no ='A'
then cast(isnull(b.fee, 0) as decimal(30, 2))
else 0 end),
a.fee2 = isnull(a.fee2, 0)
+ (case when c.fee_no ='B'
then cast(isnull(c.fee, 0) as decimal(30,2))
else 0 end)
from table1 a
inner join table2 b on a.id = b.id and b.fee_no = 'A'
inner join table2 c on a.id = c.id and c.fee_no = 'B'

Group rows with missing values in each row

I have got a table in SQL Server 2008 looking like this
FIELD1;FIELD2;FIELD3;FIELD4
-------------------------------
TEST1 ;AAAAAA;NULL ;NULL
TEST1 ;NULL ;BBBBBB;NULL
TEST1 ;NULL ;NULL ;CCCC
TEST2 ;XXXXXX;NULL ;NULL
TEST2 ;NULL ;YYYYYY;NULL
TEST2 ;NULL ;NULL ;ZZZZ
TEST3 ;UUUUUU;VVVVVV;NULL
and I want a result like this:
FIELD1;FIELD2;FIELD3;FIELD4
TEST1 ;AAAAAA;BBBBBB;CCCC
TEST2 ;XXXXXX;YYYYYY;ZZZZ
TEST3 ;UUUUUU;VVVVVV;NULL
Is there a good way to achieve this?
A simple way do achieve it is to use subqueries on the select.
declare #MyTable table
(
FIELD1 varchar(50)
,FIELD2 varchar(50)
,FIELD3 varchar(50)
,FIELD4 varchar(50)
)
insert into #MyTable values
('TEST1', 'AAAAAA', NULL , NULL)
,('TEST1', NULL , 'BBBBBB', NULL)
,('TEST1', NULL , NULL , 'CCCC')
,('TEST2', 'XXXXXX', NULL , NULL)
,('TEST2', NULL ,'YYYYYY', NULL)
,('TEST2', NULL ,NULL ,'ZZZZ')
,('TEST3', 'UUUUUU','VVVVVV', NULL)
select * from #MyTable t0
select t1.FIELD1
, (select top 1 t2.FIELD2 from #MyTable t2 where t2.FIELD2 is not null and t2.FIELD1 = t1.Field1)
, (select top 1 t3.FIELD3 from #MyTable t3 where t3.FIELD3 is not null and t3.FIELD1 = t1.Field1)
, (select top 1 t4.FIELD4 from #MyTable t4 where t4.FIELD4 is not null and t4.FIELD1 = t1.Field1)
from #MyTable t1
group by t1.FIELD1
static solution is here:
SELECT a.FIELD1,a.FIELD2,b.FIELD3,c.FIELD4
FROM YourTable a
LEFT JOIN YourTable b ON a.FIELD1 = b.FIELD1 AND b.FIELD3 IS NOT NULL
LEFT JOIN YourTable c ON a.FIELD1 = c.FIELD1 AND c.FIELD4 IS NOT NULL
WHERE a.FIELD2 IS NOT NULL

Join Based On Column Value (Best Match)

I have 3 columns to base my JOIN on -> ID, Account, Cust. There can be multiple rows containing the same ID value.
I want to prioritise my JOIN on 1) ID, 2) Account, 3) Cust.
So in the example below, the UserCode that should be populated in #UserData should be 'u11z' as all columns contain a value.
How do I do this? Below my code to date...
UPDATE #UserData
SET UserCode = ur.UserCode
FROM #UserData uA
INNER JOIN UserReference ur
ON uA.ID = ur.ID
AND ((ua.Account = ur.Account) OR (ur.Account = ur.Account))
AND ((ua.Cust = ur.Cust) OR (ur.Cust = ur.Cust))
UserReference TABLE:
Cust Account ID UserCode
234 NULL 9A2346 u12x
234 Test 9A2346 u11z
NULL NULL 9A2346 u30s
#UserData TABLE:
Cust Account ID UserCode
234 Test 9A2346 NULL
Thanks!
You can try the following. I joined tables, counted the number of matches, and ranked them. Then select rank 1.
; with userCte (userCodeA, userCodeB, rank)
as
(
select a.usercode, b.usercode,
rank() over (partition by a.id order by case when a.cust = b.cust then 1 else 0 end +
case when a.account = b.account then 1 else 0 end +
case when a.id = b.id then 1 else 0 end desc) as rank
from userdata a
join userreference b
on a.id = b.id or a.account = b.account or a.id = b.id
)
select * from userCte
--update userCte
--set userCodeA = userCodeB
where rank = 1
Is this what you want? It is difficult to understand what you are asking for.
USE tempdb;
CREATE TABLE UserReference
(
ID VARCHAR(255) NULL
, Account VARCHAR(255) NULL
, Cust INT NULL
, UserCode VARCHAR(255)
);
INSERT INTO UserReference VALUES ('9A2346', NULL, 234, 'A');
INSERT INTO UserReference VALUES ('9A2346', 'TEST', 234, 'B');
INSERT INTO UserReference VALUES ('9A2346', NULL, NULL, 'C');
DECLARE #UserData TABLE
(
ID VARCHAR(255) NULL
, Account VARCHAR(255) NULL
, Cust INT NULL
, UserCode VARCHAR(255)
);
INSERT INTO #UserData
SELECT UR.ID, UR.Account, UR.Cust, NULL
FROM dbo.UserReference UR;
UPDATE #UserData
SET UserCode = ur.UserCode
FROM #UserData uA
INNER JOIN UserReference ur
ON uA.ID = ur.ID
AND ua.Account = ur.Account
AND ua.Cust = ur.Cust;
SELECT *
FROM #UserData;
Results of the last SELECT :
If I understood your question correctly...
And if any col in a row having a null value will drop the priority then you can use a query something like below to check the count of null values in a row, this might not be a complete answer, but a possible approach...
SELECT count(*)
FROM TableName
WHERE Col1 IS NULL and Col2 is null

Resources