Related
I want to import data from this SQL table:
CREATE TABLE [dbo].[TempExchangeRates](
[currency (Libellés)] [nvarchar](255) NULL,
[Currency Code] [nvarchar](255) NULL,
[2019-03] [float] NULL,
[2019-04] [float] NULL,
[2019-05] [float] NULL,
[2019-06] [float] NULL,
[2019-07] [float] NULL,
[2019-08] [float] NULL,
[2019-09] [float] NULL,
[2019-10] [float] NULL,
[2019-11] [float] NULL,
[2019-12] [float] NULL,
[2020-01] [float] NULL,
[2020-02] [float] NULL
)
With sample data:
To this one:
CREATE TABLE [dbo].[ExchangeRates]
(
[IdExchangeRate] [uniqueidentifier] NOT NULL,
[ExchangeRateCode] [nvarchar](10) NULL,
[ExchangeRatePeriodStartDate] [datetime] NULL,
[ExchangeRatePeriodEndDate] [datetime] NULL,
[ExchangeRateValue] [decimal](20, 5) NULL,
[CurrencyCode] [nvarchar](10) NULL,
)
Now I want to call a stored procedure to get fill the real table like that:
I start with stored procedure like that but I'm not sure how I could do that
------------------------- 3. Declare StartDateTable --------------------
DECLARE #StartDateExchangeRate TABLE
(
rowid INT IDENTITY(1,1) NOT NULL,
value float,
startDate date
)
-- Insert Into #StartDateExchangeRate(value, startDate)
--This finds the start dates by finding unmatched values
--SELECT id,value
-- from ExchangeRates
------------------------- 2. Declare EndDateTable --------------------
DECLARE #EndDateExchangeRate TABLE
(
EndDate date
)
Insert Into #ENdDateExchangeRate(EndDate)
--This finds the start dates by finding unmatched values
SELECT EOMONTH(startdate)
FROM #StartDateExchangeRate As ER1
-------------------------3. Join NotYet--------------------------
This question is lacking in details
Assuming the TempExchangeRates columns will vary as time goes on, here is a option that will dynamically UNPIVOT the data so it can be inserted into your final structure.
Example (or dbFiddle)
Select ExchangeRateCode = A.[Currency Code]
,ExchangeRatePeriodStartDate = period
,ExchangeRatePeriodEndDate = EOMonth(period)
,ExchangeRateValue = B.Value
,CurrencyCode = replace(upper(A.[currency (Libellés)]),' ','')
,CreatedBy = 'SomeString'
,CreatededAt = getdate()
From [TempExchangeRates] A
Cross Apply ( Select period = try_convert(date,[Key]+'-01')
,Value = try_convert(float,value)
From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper ))
Where [Key] not in ('currency (Libellés)','Currency Code')
) B
Returns
This question already has an answer here:
operation not allowed when the object is closed when running more advanced query
(1 answer)
Closed 6 years ago.
I am trying to query a SQL Server 2008 instance from VBScript.
I know my connection is working because when I use a simple query such as the one below it works fine.
sfQuery2 = "SELECT TOP 10 * FROM [DB].[schema].[table]"
The one thing I am unsure about is the user that I am connected as has read only rights. Not sure if the userid will be able to create temp tables if they are read only. I did run the same query from SQL Server with this user and the query worked. But when I try to run this with the same user from vbscript when I try to read the record set the error I get is.....
ADODB.Recordset: Operation is not allowed when the object is closed.
sfQuery2 = "CREATE TABLE #Temp1 ([LOGNAME] [nvarchar](20) NULL, [MESSAGE_TYPE] [int] NULL, [COMPONENT] [nvarchar](50) NULL, [LOGTIME] [nvarchar](17) NOT NULL, [SUB_SYSTEM] [nvarchar](40) NULL, [STACK_ID] [nvarchar](120) NULL, [SUBSTACK_ID] [int] NULL, [MESSAGE] [nvarchar](1800) NULL, [DETAIL] [nvarchar](1800) NULL ) INSERT INTO #Temp1 SELECT DISTINCT [LOGNAME], [MESSAGE_TYPE], [COMPONENT], LOGTIME, [SUB_SYSTEM], [STACK_ID], [SUBSTACK_ID], [MESSAGE], [DETAIL] FROM [DB].[schema].[table] WHERE cast(LEFT(LOGTIME,8) as date) = cast(getdate() -1 as date) AND [MESSAGE] LIKE '%Exporter->Archive' CREATE TABLE #Temp2 ([LOGNAME] [nvarchar](20) NULL, [MESSAGE_TYPE] [int] NULL, [COMPONENT] [nvarchar](50) NULL, [LOGTIME] [nvarchar](17) NOT NULL, [SUB_SYSTEM] [nvarchar](40) NULL, [STACK_ID] [nvarchar](120) NULL, [SUBSTACK_ID] [int] NULL, [MESSAGE] [nvarchar](1800) NULL, [DETAIL] [nvarchar](1800) NULL ) INSERT INTO #Temp2 SELECT DISTINCT [LOGNAME], [MESSAGE_TYPE], [COMPONENT],cast(LEFT(LOGTIME,8) as date) AS YesterdayDate, [SUB_SYSTEM], [STACK_ID], [SUBSTACK_ID], [MESSAGE], [DETAIL] FROM [DB].[schema].[table] WHERE cast(LEFT(LOGTIME,8) as date) = cast(getdate() -1 as date) AND [DETAIL] LIKE 'USER:%' SELECT * FROM ( SELECT RIGHT(b.DETAIL, 7) AS AXAID, cast(LEFT(a.LOGTIME,8) as date) AS [DATE], b.STACK_ID, ROW_NUMBER() OVER(PARTITION by b.STACK_ID ORDER BY a.LOGTIME DESC) rn FROM #Temp1 AS a INNER JOIN #Temp2 AS b ON a.STACK_ID = b.STACK_ID WHERE a.[MESSAGE] LIKE '%Exporter->Archive' ) a WHERE rn = 1 "
oSfRs.Open sfQuery2, oSfCn
if osfrs.BOF then
Debug "There are NO results"
else
Debug "There is data in the Record Set"
end if
I am not sure if it is a syntax error with my SQL or if there it possibly because the rights of the user. Any help would be appreciate.
Please let me know if more information is needed.
For those struggling to read the SQL here is a formatted version
CREATE TABLE #Temp1 (
[LOGNAME] [nvarchar](20) NULL,
[MESSAGE_TYPE] [int] NULL,
[COMPONENT] [nvarchar](50) NULL,
[LOGTIME] [nvarchar](17) NOT NULL,
[SUB_SYSTEM] [nvarchar](40) NULL,
[STACK_ID] [nvarchar](120) NULL,
[SUBSTACK_ID] [int] NULL,
[MESSAGE] [nvarchar](1800) NULL,
[DETAIL] [nvarchar](1800) NULL
)
INSERT INTO #Temp1
SELECT DISTINCT [LOGNAME], [MESSAGE_TYPE], [COMPONENT], LOGTIME, [SUB_SYSTEM]
, [STACK_ID], [SUBSTACK_ID], [MESSAGE], [DETAIL]
FROM [DB].[schema].[table]
WHERE cast(LEFT(LOGTIME,8) as date) = cast(getdate() -1 as date)
AND [MESSAGE] LIKE '%Exporter->Archive'
CREATE TABLE #Temp2 (
[LOGNAME] [nvarchar](20) NULL,
[MESSAGE_TYPE] [int] NULL,
[COMPONENT] [nvarchar](50) NULL,
[LOGTIME] [nvarchar](17) NOT NULL,
[SUB_SYSTEM] [nvarchar](40) NULL,
[STACK_ID] [nvarchar](120) NULL,
[SUBSTACK_ID] [int] NULL,
[MESSAGE] [nvarchar](1800) NULL,
[DETAIL] [nvarchar](1800) NULL
)
INSERT INTO #Temp2 SELECT DISTINCT [LOGNAME], [MESSAGE_TYPE], [COMPONENT]
, cast(LEFT(LOGTIME,8) as date) AS YesterdayDate
, [SUB_SYSTEM], [STACK_ID], [SUBSTACK_ID], [MESSAGE], [DETAIL]
FROM [DB].[schema].[table]
WHERE cast(LEFT(LOGTIME,8) as date) = cast(getdate() -1 as date)
AND [DETAIL] LIKE 'USER:%'
SELECT *
FROM (
SELECT RIGHT(b.DETAIL, 7) AS AXAID, cast(LEFT(a.LOGTIME,8) as date) AS [DATE]
, b.STACK_ID, ROW_NUMBER() OVER(PARTITION by b.STACK_ID ORDER BY a.LOGTIME DESC) rn
FROM #Temp1 AS a
INNER JOIN #Temp2 AS b ON a.STACK_ID = b.STACK_ID
WHERE a.[MESSAGE] LIKE '%Exporter->Archive'
) a WHERE rn = 1
Resolved by comment by Lankymart.
The resolution was to add SET NOCOUNT ON to the beginning of my query.
I'm faced with the same problem related here Building a snapshot table from audit records. The code bellow solve partially my problem
Select * into #temp from (
SELECT Audit.PrimaryKeyValue as ID,Audit.FieldName,OldValue FROM audit left JOIN (
SELECT Audit.FieldName,Audit.PrimaryKeyValue, MAX(UpdateDate) AS dateadded FROM audit GROUP BY FieldName,PrimaryKeyValue
) maxtimestamp ON audit.FieldName = maxtimestamp.FieldName AND audit.updateDate = maxtimestamp.dateadded
where PrimaryKeyField='Id' and cast(UpdateDate as date)<=#Data) src
pivot(
max(src.OldValue)
for FieldName in (Centrala,ID_Grup,Pi, Ci, Pmt, Pneta, Rpp, Pd, UD, Suport1, Suport2, Suport3, Stare,
Motiv, Observatii, Comentarii, Un, Data_ADD, Modified_Date, Scada, Fuel_base)
) piv;
How to obtain a snapshot of a table based on records from audit trail table at a given moment.
By copying actual table in a temp one and by updating values from it based on content of audit is a solution?
My English is poor!
Thanks!!!
The structure of the primary table is:
[ID] [int] IDENTITY(1,1) NOT NULL,
[Centrala] [int] NOT NULL,
[ID_grup] [nvarchar](50) NULL,
[Pi] [float] NULL,
[Ci] [float] NULL,
[Pmt] [float] NULL,
[Pneta] [float] NULL,
[Rpp] [float] NULL,
[Pd] [float] NULL,
[UD] [nvarchar](50) NULL,
[Suport1] [nvarchar](255) NULL,
[Suport2] [nvarchar](255) NULL,
[Suport3] [nvarchar](255) NULL,
[Stare] [int] NULL,
[Motiv] [nvarchar](max) NULL,
[Observatii] [nvarchar](max) NULL,
[Comentarii] [nvarchar](max) NULL,
[Un] [varchar](10) NULL,
[Data_ADD] [date] NULL,
[Modified_Date] [date] NULL,
[Scada] [nvarchar](100) NULL,
[Fuel_base] [nvarchar](255) NULL,
and the structure of the Audit table is:
[AuditID] [int] IDENTITY(1,1) NOT NULL,
[Type] [char](1) NULL,
[TableName] [varchar](128) NULL,
[PrimaryKeyField] [varchar](1000) NULL,
[PrimaryKeyValue] [varchar](1000) NULL,
[FieldName] [varchar](128) NULL,
[OldValue] [varchar](1000) NULL,
[NewValue] [varchar](1000) NULL,
[UpdateDate] [datetime] NULL,
[UserName] [varchar](128) NULL
Users can modify values in primary table inclusive deleting entire rows and Audit table catch all modifications.I have to do a report with content of primary table at certain date back in time. I think the columns name in Audit table are expressive, Type has three values 'U','I','D' for update,insert and delete actions. Another problem is that if the Audit table contain modification for rows in primary table and the date for snapshot is lower than updateDate in Audit then I have to choose OldValue else NewValue. It is correct?
Thank you #Nick.McDermaid for your reply!!
I found an extremely ugly solution, but I think it works fine by now
Declare #data date
select #data='2016.02.2'
select * into #Grup1 from Grupuri
--Apply to actual values most oldest values from Audit
select * into #temp from (
SELECT
Audit.PrimaryKeyValue as ID,Audit.FieldName,OldValue
FROM audit inner JOIN (
SELECT Audit.FieldName,Audit.PrimaryKeyValue, min(UpdateDate) AS dateadded FROM audit GROUP BY FieldName,PrimaryKeyValue
) maxtimestamp ON audit.FieldName = maxtimestamp.FieldName AND audit.updateDate = maxtimestamp.dateadded
where PrimaryKeyField='Id' and TableName='Grupuri' ) src
pivot(
max(src.OldValue)
for FieldName in (Centrala,ID_Grup,Pi, Ci, Pmt, Pneta, Rpp, Pd, UD, Suport1, Suport2, Suport3, Stare,
Motiv, Observatii, Comentarii, Un, Data_ADD, Modified_Date, Scada, Fuel_base)
) piv;
UPDATE #Grup1 SET Pi= (case When b.Pi is not null then b.Pi else #Grup1.Pi end),
Ci=case When b.Ci is not null then b.Ci else #Grup1.Ci end,
Pmt=case When b.Pmt is not null then b.Pmt else #Grup1.Pmt end,
Pneta=case When b.Pneta is not null then b.Pneta else #Grup1.Pneta end,
Rpp=case When b.Rpp is not null then b.Rpp else #Grup1.Rpp end,
Pd=case When b.Pd is not null then b.Pd else #Grup1.Pd end,
UD=case When b.Ud is not null then b.Ud else NULL end,
Suport1=case When b.Suport1 is not null then b.Suport1 else #Grup1.Suport1 end,
Suport2=case When b.Suport2 is not null then b.Suport2 else #Grup1.Suport2 end,
Suport3=case When b.Suport3 is not null then b.Suport3 else #Grup1.Suport3 end,
Stare=case When b.Stare is not null then b.Stare else #Grup1.Stare end,
Motiv=case When b.Motiv is not null then b.Motiv else #Grup1.Motiv end,
Observatii=case When b.Observatii is not null then b.Observatii else #Grup1.Observatii end,
Comentarii=case When b.Comentarii is not null then b.Comentarii else #Grup1.Comentarii end,
Un=case When b.Un is not null then b.Un else #Grup1.Un end,
Scada= case When b.Scada is not null then b.Scada else #Grup1.Scada end,
Fuel_base=case When b.Fuel_base is not null then b.Fuel_base else #Grup1.Fuel_base end
FROM #temp b WHERE #Grup1.id = b.id
--Apply new values updated up to #data
select * into #temp1 from (
SELECT
Audit.PrimaryKeyValue as ID,Audit.FieldName,NewValue
FROM audit left JOIN (
SELECT Audit.FieldName,Audit.PrimaryKeyValue, MAX(UpdateDate) AS dateadded FROM audit GROUP BY FieldName,PrimaryKeyValue
) maxtimestamp ON audit.FieldName = maxtimestamp.FieldName AND audit.updateDate = maxtimestamp.dateadded
where PrimaryKeyField='Id' and TableName='Grupuri'
and cast(UpdateDate as date) <=#Data) src
pivot(
max(src.NewValue)
for FieldName in (Centrala,ID_Grup,Pi, Ci, Pmt, Pneta, Rpp, Pd, UD, Suport1, Suport2, Suport3, Stare,
Motiv, Observatii, Comentarii, Un, Data_ADD, Modified_Date, Scada, Fuel_base)) piv;
UPDATE #Grup1 SET Pi= (case When b.Pi is not null then b.Pi else #Grup1.Pi end),
Ci=case When b.Ci is not null then b.Ci else #Grup1.Ci end,
Pmt=case When b.Pmt is not null then b.Pmt else #Grup1.Pmt end,
Pneta=case When b.Pneta is not null then b.Pneta else #Grup1.Pneta end,
Rpp=case When b.Rpp is not null then b.Rpp else #Grup1.Rpp end,
Pd=case When b.Pd is not null then b.Pd else #Grup1.Pd end,
UD=case When b.Ud is not null then b.Ud else '-' end,
Suport1=case When b.Suport1 is not null then b.Suport1 else #Grup1.Suport1 end,
Suport2=case When b.Suport2 is not null then b.Suport2 else #Grup1.Suport2 end,
Suport3=case When b.Suport3 is not null then b.Suport3 else #Grup1.Suport3 end,
Stare=case When b.Stare is not null then b.Stare else #Grup1.Stare end,
Motiv=case When b.Motiv is not null then b.Motiv else #Grup1.Motiv end,
Observatii=case When b.Observatii is not null then b.Observatii else #Grup1.Observatii end,
Comentarii=case When b.Comentarii is not null then b.Comentarii else #Grup1.Comentarii end,
Un=case When b.Un is not null then b.Un else #Grup1.Un end,
Scada= case When b.Scada is not null then b.Scada else #Grup1.Scada end,
Fuel_base=case When b.Fuel_base is not null then b.Fuel_base else #Grup1.Fuel_base end
FROM #temp1 b
WHERE #Grup1.id = b.id
Delete from #Grup1 where Data_ADD>#data
Select * from #Grup1
union
Select Old_ID,Centrala,ID_Grup,Pi, Ci, Pmt, Pneta, Rpp, Pd, UD, Suport1,Suport2, Suport3, Stare, Motiv,
Observatii, Comentarii, Un, Data_ADD, Modified_Date, Scada, Fuel_base From DeletedGrupuri where Deleted<=#Data and Old_ID is not null order by ID
drop table #temp
drop table #temp1
drop table #Grup1
If someone has a better solution or can improve this code please help me. Also I'm open to modify the design of table Audit to simplify this process.
Thank You!
I'm a rookie to SQL Server. I'm using SQL Server 2008 R2. I have created two tables called adding_hanger and allot as follows
CREATE TABLE [dbo].[adding_hanger]
(
[End_Id] [bigint] IDENTITY(1,1) NOT NULL,
[Hanger_Location] [char](10) NOT NULL,
[Hanger_Capacity] [int] NOT NULL,
[Hanger_Id] AS ((CONVERT([varchar](100),substring([Hanger_Location],(1),(3)),0)+'101')+CONVERT([varchar](100),[End_Id],0)) PERSISTED NOT NULL,
[Manager_Name] [varchar](15) NOT NULL,
[Manager_Id] AS ((CONVERT([varchar](4),substring([Social_Security_No],(8),(4)),0)+'31')+CONVERT([varchar](100),[End_Id],0)) PERSISTED NOT NULL,
[Manager_Password] AS ((CONVERT([varchar](3),substring([Manager_Name],(1),(3)),0)+'#')+CONVERT([varchar](3),substring([Hanger_Location],(1),(3)),0)),
[Social_Security_No] [varchar](15) NOT NULL,
[Date_of_Birth] [datetime] NOT NULL,
[Gender] [varchar](8) NOT NULL,
[Mobile_No] [varchar](50) NOT NULL,
[Email_Address] [varchar](30) NOT NULL,
[House_No] [varchar](10) NOT NULL,
[Address_Line_1] [varchar](30) NOT NULL,
[Address_id] AS ((CONVERT([varchar](100),substring([City],(1),(3)),0)+'31')+CONVERT([varchar](100),[End_Id],0)) PERSISTED NOT NULL,
[City] [char](15) NOT NULL,
[State] [char](15) NOT NULL,
[Country] [char](15) NOT NULL,
[Pin_No] [int] NOT NULL
)
CREATE TABLE [dbo].[allot]
(
[Fromdate] [datetime] NULL,
[todate] [datetime] NULL,
[hangarlocation] [char](10) NULL,
[hangarno] [varchar](100) NULL,
[planeid] [varchar](100) NULL
)
How do I fetch the details of the available hangers that are not allotted within a given range of from and to dates given as input and also not exceeding the capacity of the hanger if allocated already?
First, your spelling of 'hangar' is inconsistent and should be addressed.
I'm assuming that the hangar capacity represents how many allots you can store in that hangar? If so, the hangar capacity might vary over a given timeframe as allots are added/removed (according to FromDate and ToDate), so your question isn't clear. If you want a hangar that definitely has a space free over a given period, I would use:
declare #from_date datetime, #end_date datetime, #i int
-- Set your start and end dates (replace the dates below with the correct ones)
set #from_date = '2016-07-01'
set #to_date = '2016-07-31'
set #i = 1 -- counter
-- Create a table of dates
select #from_date as date into #dates
while dateadd(day,#i,#from_date) <= #to_date
begin
insert into #dates values (dateadd(day,#i,#from_date))
end
-- Create table of date, hangar_id, hangar_capacity
select date, hangar_id, hangar_capacity
into #dates_by_hangar
from adding_hangar
inner join #dates on 1 = 1
-- Table showing hangars with at least one free space on every date in the range
select hangar_id from (
-- 2. Table showing hangar space free on each date
select a.*, a.hanger_capacity - isnull(b.allots_in_hangar,0) as hangar_space_free
from #dates_by_hangar a
left outer join (
-- 1. Table showing number of allots in each hangar on a given date
select date, hangar_no, sum(case when b.hangar_no is not null then 1 else 0 end) as allots_in_hangar
from #dates a
left outer join allot b
on a.date between b.fromdate and b.todate
group by date, hangar_no) b
on a.hangar_id = b.hangar_no
and a.date = b.date
)
group by hangar_no
having max(hangar_space_free) >= 1
SELECT ah.* from [adding_hanger] AS ah
INNER JOIN [allot] ON allot.hangarlocation = ah.Hanger_Location
WHERE (allot.Fromdate < <input_from_date> OR allot.todate > <input_to_date>)
OR (allot.Fromdate >= <input_from_date> AND allot.todate <= <input_to_date> AND ah.Hanger_Capacity <= <input_capacity>)
The task itself is very basic. I have a transaction table that moves a certain quantity of a product in or out of stock. It becomes a bit more difficult knowing that a product can be composed from multiple 'base' products and only the base products may exist in stock.
My current trigger works but works like this:
Create temporary table that can combine inserted, deleted and composed products.
Add inserted non composed products to this temp table
Add inserted composed products
Subtract deleted non composed products
Subtract deleted composed products
I now have a table containing all transactions of non composed products. But i.e. with an update of a row, the same product is added twice. Once subtracting the old value and once adding the new value.
Create second temporary table for the joined non composed products
Take a sum of the products and put these into the new temp table
Merge the stock with this temp table
Again.. my trigger works fine and i'm having no performance problem (yet) but I feel i'm missing something. I bet there is someone around here with a better solution then mine.
My tables and sample data: (fiddle here)
CREATE TABLE [dbo].[Product](
[id] [int] IDENTITY(1,1) NOT NULL,
[plantId] [int] NOT NULL,
[reference] [nvarchar](50) NOT NULL,
[composed] [bit] NOT NULL DEFAULT ((0)),
[name] [nvarchar](max) NOT NULL,
[unit] [nvarchar](50) NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
INSERT INTO [dbo].[Product] VALUES (2, 'FILLER VULPROF 2 BR', 0, 'FILLER VULPROF 2 BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'K 0/2GEW BR', 0, 'K 0/2GEW BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'K 14/20 BR', 0, 'K 14/20 BR', 'ton', GETDATE());
INSERT INTO [dbo].[Product] VALUES (2, 'KWS BR 3A31', 1, 'KWS BR 3A31', 'ton', GETDATE());
CREATE TABLE [dbo].[ProductComposition](
[id] [int] IDENTITY(1,1) NOT NULL,
[productId] [int] NOT NULL,
[parentId] [int] NOT NULL, -- This is the parent product
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
INSERT INTO [dbo].[ProductComposition] VALUES (1, 4, 0.001, GETDATE());
INSERT INTO [dbo].[ProductComposition] VALUES (3, 4, 0.001, GETDATE());
CREATE TABLE [dbo].[Transaction](
[id] [int] IDENTITY(1,1) NOT NULL,
[load] [bit] NOT NULL,
[plantId] [int] NOT NULL,
[vehicleId] [int] NOT NULL,
[productId] [int] NOT NULL,
[contactId] [int] NOT NULL,
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate()),
[isSynched] [bit] NOT NULL CONSTRAINT [DF_Transaction_isSynched] DEFAULT ((0))
);
CREATE TABLE [dbo].[Stock](
[id] [int] IDENTITY(1,1) NOT NULL,
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL,
[dateUpdate] [datetime] NOT NULL DEFAULT (getdate())
);
My Trigger:
ALTER TRIGGER [dbo].[StockCalculate]
ON [dbo].[Transaction]
AFTER INSERT, UPDATE, DELETE AS
BEGIN
-- Create temporary table
CREATE TABLE #TransactionsComposed (
[load] [bit] NOT NULL,
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL
);
-- Insert basic materials
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
[Inserted].[load],
[Inserted].[plantId],
[Inserted].[productId],
[Inserted].[quantity]
FROM
[Inserted]
INNER JOIN [Product] ON [Product].[id] = [Inserted].[productId]
WHERE
[Product].[composed] = 0;
-- Insert operations
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
[Inserted].[load],
[Inserted].[plantId],
[ProductComposition].[productId],
([Inserted].[quantity] * [ProductComposition].[quantity])
FROM
[Inserted]
INNER JOIN [Product] ON [Product].[id] = [Inserted].[productId]
INNER JOIN [ProductComposition] ON [ProductComposition].[parentId] = [Product].[id]
WHERE
[Product].[composed] = 1;
-- Insert basic materials but ALTER it's load status.
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
CASE [Deleted].[load]
WHEN 0 THEN 1
WHEN 1 THEN 0
END,
[Deleted].[plantId],
[Deleted].[productId],
[Deleted].[quantity]
FROM
[Deleted]
INNER JOIN [Product] ON [Product].[id] = [Deleted].[productId]
WHERE
[Product].[composed] = 0;
-- Insert operations but ALTER it's load status.
INSERT INTO #TransactionsComposed (
[load], [plantId], [productId], [quantity])
SELECT
CASE [Deleted].[load]
WHEN 0 THEN 1
WHEN 1 THEN 0
END,
[Deleted].[plantId],
[ProductComposition].[productId],
([Deleted].[quantity] * [ProductComposition].[quantity])
FROM
[Deleted]
INNER JOIN [Product] ON [Product].[id] = [Deleted].[productId]
INNER JOIN [ProductComposition] ON [ProductComposition].[parentId] = [Product].[id]
WHERE
[Product].[composed] = 1;
-- Prepare multiple products for merge
CREATE TABLE #TransactionsJoined (
[plantId] [int] NOT NULL,
[productId] [int] NOT NULL,
[quantity] [float] NOT NULL
);
INSERT INTO #TransactionsJoined
([plantId], [productId], [quantity])
SELECT
[plantId],
[productId],
SUM(CASE [load]
WHEN 0 THEN [quantity]
WHEN 1 THEN 0 - [quantity]
END)
FROM
#TransactionsComposed
GROUP BY [plantId], [productId]
-- Merge composed transactions into the stock
MERGE [Stock]
USING #TransactionsJoined
ON [Stock].[plantId]=#TransactionsJoined.[plantId]
AND [Stock].[productId]=#TransactionsJoined.[productId]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([plantId], [productId], [quantity])
VALUES (
#TransactionsJoined.[plantId],
#TransactionsJoined.[productId],
#TransactionsJoined.[quantity])
WHEN MATCHED THEN
UPDATE SET
[Stock].[quantity] = [Stock].[quantity] + #TransactionsJoined.[quantity],
[Stock].[dateUpdate] = GETDATE();
END