how can i run sqlserver trigger from C# - c#

I have multiple trigger in a single sqlserver table some create description of a product by concatenating different fields, some get data from another table and a trigger which insert a product to another table.
I want to run the trigger which insert's data to another database table on button click from C#.
here is my code which inserts or setup product into another table
Create TRIGGER [dbo].[WHL-MISYSSETUP]
ON [dbo].[WHEELS]
AFTER insert,UPDATE
AS
BEGIN
IF TRIGGER_NESTLEVEL() > 1
RETURN
---------------------------------------------------// INSERT PRODUCT INFO TO MASTER TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
BEGIN
IF NOT EXISTS (SELECT * FROM [MITESTCO].dbo.[MIITEM]
WHERE [MITESTCO].dbo.[MIITEM].itemId IN (select [STOCK NO] from inserted) and [MITESTCO].dbo.[MIITEM].descr IN (select [PURCHASE DESCRIPTION] from inserted))
BEGIN
INSERT INTO [MITESTCO].dbo.MIITEM
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])--,[unitWgt]
SELECT [STOCK NO], [PURCHASE DESCRIPTION2], [SALES DESCRIPTION2], [STOCK NO] ,'EA' ,'EA' ,'1',[WORK INSTRUCTION-WHL], '2','0'--,[APPROX. WGT.]
FROM [inserted]
WHERE [STOCK NO] NOT IN (SELECT [itemId] FROM [MITESTCO].dbo.[MIITEM] WHERE itemId NOT LIKE '*-CI')
AND [MAKE / BUY]='Make';
END
END
SET ANSI_WARNINGS ON;
SET ANSI_WARNINGS off;
BEGIN
IF NOT EXISTS (SELECT * FROM [MITESTCO].dbo.[MIITEM]
WHERE [MITESTCO].dbo.[MIITEM].itemId IN (select [STOCK NO] from inserted) and [MITESTCO].dbo.[MIITEM].descr IN (select [PURCHASE DESCRIPTION] from inserted))
BEGIN
INSERT INTO [MITESTCO].dbo.MIITEM
([itemId], [descr],[xdesc],[sales] ,[uOfM] ,[poUOfM] ,[uConvFact],[ref],[type],[status])--,[unitWgt]
SELECT [STOCK NO], [PURCHASE DESCRIPTION2], [SALES DESCRIPTION2], [STOCK NO] ,'EA' ,'EA' ,'1',[WORK INSTRUCTION-WHL], '2','0'--,[APPROX. WGT.]
FROM [inserted]
WHERE [STOCK NO] NOT IN (SELECT [itemId] FROM [MITESTCO].dbo.[MIITEM] WHERE itemId NOT LIKE '*-CI')
AND [MAKE / BUY]='BUY';
END
END
SET ANSI_WARNINGS on;
---------------------------------------------------// INSERT PRODUCT INFO TO BOM HEADER TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
DECLARE #d DATETIME = GETDATE();
INSERT INTO [MITESTCO].[dbo].[MIBOMH]
([bomItem], [bomRev], [rollup], [mult], [autoBuild], [assyLead],[revCmnt],[author],[descr],[qPerLead],[lstMainDt],[revDate],[effStartDate],[ovride] )
-- DECLARE #d DATETIME = GETDATE();
SELECT [STOCK NO], [bomRev], '1', '1', '1', '3','SYNC FROM TV','username','WHL FROM PDM','0', FORMAT(#d, 'yyyy-MM-dd HH\:mm\:ss\.fff', 'en-US') AS 'Format#1',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2',FORMAT(#d, 'yyyyMMdd' , 'en-US') AS 'Format#2','0'
FROM [INSERTED]
WHERE [STOCK NO] NOT IN (SELECT [MITESTCO].[dbo].[MIBOMH].[bomItem] FROM [MITESTCO].[dbo].[MIBOMH] where bomRev != [bomRev])
AND [STOCK NO] IN (SELECT [MITESTCO].[dbo].[MIITEM].[ItemId] FROM [MITESTCO].[dbo].[MIITEM] where type='2');
SET ANSI_WARNINGS ON;
---------------------------------------------------// INSERT PRODUCT INFO TO BOM DETAIL TABLE ----------------------------------------------------------------
SET ANSI_WARNINGS OFF;
;with cte as (
select
[STOCK NO]
, u.rev
, bomEntry = row_number() over (order by u.ordinal)
, u.Partid
, u.Qty--='1'
, cmnt = ''
, srcLoc = 'DS'
, dType = '0'
, lead = '0'
, lineNbr = row_number() over (order by u.ordinal)
--, bomRev
from [inserted]
cross apply (values
('1',[bomRev],1,[BOM-WHEEL PN])
,('1',[bomRev],2,[BOM - RIM PN])
,('1',[bomRev],3,[BOM - SECONDARY DISC PN])
,('1',[bomRev],4,[BOM - FIN DISC PN])
,('1',[bomRev],5,[BOM - FLAT FIN DISC PN])
,([WHL BOM QTY 1],[bomRev],6,[WHL BOM PART 1 PN])
,([WHL BOM QTY 2],[bomRev],7,[WHL BOM PART 2 PN])
,([WHL BOM QTY 3],[bomRev],8,[WHL BOM PART 3 PN])
,([WHL BOM QTY 4],[bomRev],9,[WHL BOM PART 4 PN])
,([WHL BOM QTY 5],[bomRev],10,[WHL BOM PART 5 PN])
,('1',[bomRev],11,[COLOR-PN])
) u (Qty,rev, ordinal, partId)
where nullif(u.partId, '') is not null
)
INSERT INTO [MITESTCO].dbo.[MIBOMD]
([bomItem], [bomRev], [bomEntry], [partId], [qty],[cmnt],[srcLoc],[dType],[lead],[lineNbr])
select
cte.[STOCK NO]
, cte.rev
, cte.bomEntry
, cte.Partid
, cte.Qty
, cte.cmnt
, cte.srcLoc
, cte.dType
, cte.lead
, cte.lineNbr
from cte
where not exists (
select 1
from [MITESTCO].dbo.[MIBOMD] w
where w.[bomItem] = cte.[STOCK NO]
and w.[bomRev] = cte.rev
and w.[bomEntry]= cte.bomEntry
);
SET ANSI_WARNINGS ON;
---------------------------------------------------// end Creates BOM STRUCTURE ----------------------------------------------------------------
The main reason that i want to run it manually or on button click event is because for some reason this trigger run before computed fields and some of the triggers so i don't get complete information to insert to the other table for the first time both after insert or update. i tried EXEC sp_settriggerorder #triggername=N'[dbo].[WHL-MISYSSETUP]', #order=N'Last', #stmttype=N'INSERT' but that doesnt help me i get the same problem
when new product created or updated i want to run this from C# on button click_event. Any idea will appreciated

Triggers can't be called. They should be triggered automatically and for every row, in your case:
AFTER insert,UPDATE.
If you need to run this query after clicking some button what I suggest is instead of using a trigger, create a new stored procedure.
The problem here is that you will have to know what are the [STOCK NO] you need to update without using the inserted table.

Related

Counting field by day in mssql

I have a table with Scheduling slots called:
ScheduleSlots
Fields:
id (int)
scheduleID (int)
time (datetime)
availableslots (int)
CalendarGroupID (int)
Level (int)
enabled (bit)
I want to setup a gridview where I take all of the dates and count enabled and disabled for each day.
I am not sure how to go about writing the sql statement to do this.
ie.
Date Enabled Disabled
3/31/2021 20 20
4/1/2021 10 30
SELECT Time, scheduleID,
(SELECT COUNT(Enabled) FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1 AND Enabled=1) as Enabled,
(SELECT COUNT(Enabled) FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1 AND Enabled=0) as Disabled
FROM [dbo].[ScheduleSlots]
WHERE Cast(Time as Date)>='2021-03-31' AND Cast(Time as Date)<='2021-04-01' AND CalendarGroupID=1 AND Level=1
GROUP BY scheduleID, Time
The results I end up with:
[Results][1]
You could do it without inner selects:
SELECT [Time],
SUM([Enabled]) as [Enabled],
SUM([Disabled]) as [Disabled]
FROM [dbo].[ScheduleSlots]
WHERE
[Time]>='2021-03-31'
AND [Time]<='2021-04-01'
AND CalendarGroupID=1
AND Level=1
GROUP BY Cast([Time] as Date)
It is an easy grouping query:
SELECT
CONVERT(DATE, "Time") AS "Date",
SUM(CONVERT(INT, "Enabled")) AS "Enabled",
COUNT() - SUM(CONVERT(INT, "Enabled")) AS "Disabled"
FROM "dbo"."ScheduleSlots"
WHERE "CalendarGroupID" = 1
AND "Level" = 1
GROUP BY CONVERT(DATE, "Time")
I hope I understand you correctly where you want the enable slot and diable slot for each day.
;With CTE(Transdate) as (Select Distinct([time]) from ScheduleSlots)
Select CTE.Transdate,(Select COUNT(Id) from ScheduleSlots where enabled= 1
and Transdate = CTE.Transdate) as Enable,
(Select COUNT(Id) from ScheduleSlots where enabled= 0
and Transdate = CTE.Transdate) as Disable from CTE
I inserted some records to make it clear. If I am wrong with inserted data please send me the insert scripts so, that I can test the results.
CREATE TABLE ScheduleSlots
(
id int,
scheduleID int,
[time] datetime,
availableslots int,
CalendarGroupID int,
[Level] int,
[enabled] bit
)
----insert into ScheduleSlots values(1,1,'2021-03-31',40,1,1,20)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,0)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-03-31',20,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-04-01',40,1,1,1)
INSERT INTO ScheduleSlots VALUES(1,1,'2021-04-01',40,1,1,0)
SELECT DISTINCT
[time] AS [Date]
,SUM(availableslots) OVER(PARTITION BY [time] ORDER BY [time]) AS [avaibale]
,SUM(CAST([enabled] AS INT)) OVER(PARTITION BY [time] ORDER BY [time]) AS [Enabled]
,SUM(availableslots) OVER(PARTITION BY [time] ORDER BY [time]) -
SUM(CAST([enabled] AS INT)) OVER(PARTITION BY [time] ORDER BY [time]) AS [Disabled]
FROM ScheduleSlots
Answer I got:

Duplicate Entry Insertion while insertion of DataTable in Stored Procedure

I'm inserting DataTable in Database using StoredProcedure but the issue is, its inserting twice the actual number of entries of DataTable to be inserted, the procedure is below, kindly guide me, if I'm using wrong approach, why its duplicating the rows? The return which is required is working fine.
Thanks In Advance
ALTER PROCEDURE [dbo].[proc_InsertStore_Recvry]
(#dt_Recovery Recovery_Store READONLY)
AS
Declare #RecoveryIDs as Table (IDs int, ClientIds int)
declare #StoreID int
declare #ClientID int
declare #Arrears decimal(18, 2)
declare #NetDues decimal(18, 2)
declare #Received decimal(18, 2)
Declare #RecoveryRecID int
begin
select * into #tempTable from #dt_Recovery
declare #Count int
set #Count= (select COUNT(*) from #tempTable)
while(#Count > 0)
begin
set #Count = #Count-1
set #ClientID = (Select top 1 ClientID from #tempTable)
set #StoredID = (Select top 1 StoredID from #tempTable where ClientID=#ClientID)
set #Arrears = (Select top 1 Arrears from #tempTable where ClientID=#ClientID)
set #NetDues = (Select top 1 NDues from #tempTable where ClientID=#ClientID)
set #Received = (Select top 1 Received from #tempTable where ClientID=#ClientID)
Insert into tblRecovery (StoreID, ClientID, Arrears, NetDues, Received)
values (#StoreID,#ClientID,#Arrears,#NetDues,#Received)
select #RecoveryID = Scope_Identity()
insert into #RecoveryIDs (IDs,ClientIds) values (#RecoveryID, #ClientID )
delete from #tempTable where ClientID=#ClientID
end
Select * from #RecoveryIDs
it looks like you are using SQL Server. If yes then why are you using a while-loop to insert values into a table and return the inserted Ids?
The same can be accomplished in a far better way via the OUTPUT clause:
OUTPUT documentation
Example:
INSERT INTO tblRecovery(StoreID, ClientID, Arrears, NetDues, Received) OUTPUT INSERTED.ID, INSERTED.CLientId INTO #RecoveryIDs(IDs, ClientIds) SELECT StoredID, ClientID, Arrears, NDues, Received FROM #tempTable
Aside from that there seems to be no issue with your SQL code. So could you post the .NET code as well?

SSIS Add number to Duplicate Values in Column to make them Unique

My data has some duplicate records in only a single column. I want to filter them after running the data through a script component to take all duplicate values and append incremental numbers to them so they are unique.
Is it possible to do with with an Aggregate Component?
For example, my data may look like this:
Column1 and 2 are used as my primary Keys, so I need Column2 to be more unique with it's values.
After Appending numbers to the duplicates, it would look like this (notice 'C' does not have a number):
select tt.*, tt.col2 + '.' + rn
from ( select t.*
, row_number() over (partition by col2 order by ?) as rn
, count(*) over (partition by col2) as cnt
) tt
I noticed C does not have a number. I will leave that exercise to you. Hint use cnt.
DECLARE #a TABLE (col2 varchar(20));
INSERT INTO #a VALUES ('a'), ('a') , ('a'), ('b'), ('c'), ('c');
select aa.*, aa.col2 + '.' + cast(rn as varchar)
from ( select a.*
, row_number() over (partition by col2 order by col2) as rn
, count(*) over (partition by col2) as cnt
from #a a
) aa
where aa.cnt > 1
order by aa.col2;
update aa
set aa.col2 = aa.col2 + '.' + cast(rn as varchar)
from ( select a.*
, row_number() over (partition by col2 order by col2) as rn
, count(*) over (partition by col2) as cnt
from #a a
) aa
where aa.cnt > 1;
select * from #a a
order by a.col2;

Is it possible to transpose a table's entries and store it into a temp table in SQL Server?

I would like to transpose the data from my table and do some plottings into powerBI.
Here is how I feel up my database from my application:
using (SqlCommand cmd = connect.CreateCommand())
{
cmd.CommandText = #"INSERT INTO PoD_NewPriceList_Data
(ID, Product_Barcode, Product_Name,
Store_Price, Internet_Price, InsertDate)
VALUES (#ID, #Product_Barcode, #Product_Name,
#Store_Price, #Internet_Price, #InsertDate)";
cmd.Parameters.Add("Product_Barcode", SqlDbType.NVarChar).Value = barcode;
cmd.Parameters.Add("Product_Name", SqlDbType.NVarChar).Value = PriceList.name;
cmd.Parameters.Add("Store_Price", SqlDbType.Float).Value = Convert.ToDouble(storePrice, CultureInfo.InvariantCulture);
cmd.Parameters.Add("Internet_Price", SqlDbType.Float).Value = Convert.ToDouble(PriceList.price, CultureInfo.InvariantCulture);
cmd.Parameters.Add("InsertDate", SqlDbType.DateTime).Value = InsertDate.AddDays(2);
cmd.Parameters.Add("ID", SqlDbType.Int).Value = barcode.GetHashCode();
result = result && (cmd.ExecuteNonQuery() > 0);
}
And in SQL Server Management Studio here is how my table looks like:
SELECT
[ID], [Product_Barcode], [Product_Name],
[Store_Price], [Internet_Price], [InsertDate]
FROM
[dbo].[PoD_NewPriceList_Data]
and I get the following output:
The main issue is when trying to create the plots as requested in PowerBI I need my data to look as follows:
F5321
Product_Name Sony Xperia...
Store_Price 399
Internet_Price 327.51
InsertDate 2017.04.27
Any help would be well appreciated.
Check and modify this SQL script. I use #t table variable, replace it with your table name [PoD_NewPriceList_Data].
DECLARE #t TABLE (
id int,
product_barcode varchar(max),
product_name varchar(max),
store_price int,
internet_price decimal,
insert_date date
)
INSERT INTO #t VALUES (1,'F5321', 'Sony Xperia', 399, 255.1, '2017-04-25')
INSERT INTO #t VALUES (2,'F5833', 'Sony Xperia XZ', 458, 398.2, '2017-04-26')
INSERT INTO #t VALUES (3,'F5121', 'Sony Xperia XA Rose', 161, 155.6, '2017-04-27')
IF OBJECT_ID ('tempdb..#Unpivoted') IS NOT NULL
DROP TABLE #Unpivoted
IF OBJECT_ID ('tempdb..#Transposed') IS NOT NULL
DROP TABLE #Transposed
/* Unpivot table to get rows instead of columns */
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as rn
INTO #Unpivoted
FROM (SELECT product_barcode, product_name,
CAST(store_price as varchar(max)) store_price,
CAST(internet_price as varchar(max)) internet_price,
CAST(insert_date as varchar(max)) as insert_date
FROM #t) src
UNPIVOT (
value FOR field IN (
product_barcode, product_name, store_price, internet_price, insert_date
)
) unpiv
CREATE TABLE #Transposed
(Field varchar(50) PRIMARY KEY NOT NULL )
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = STUFF((
SELECT 'ALTER TABLE #Transposed ADD item' +
RIGHT('000' + CAST(sv.number AS VARCHAR(3)), 3) + ' varchar(max) '
FROM [master].dbo.spt_values sv
WHERE sv.[type] = 'p'
AND sv.number BETWEEN 1 AND (SELECT COUNT(*) FROM #t)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '')
Exec(#SQL) /* Dynamically create columns */
INSERT INTO #Transposed (Field) SELECT DISTINCT Field FROM #Unpivoted
/*populate field names*/
DECLARE #fieldCount int = (SELECT COUNT(*) FROM #Transposed)
/* using rn to filter proper record from transposed table */
SELECT #SQL = STUFF((
SELECT '
UPDATE #Transposed SET item' + RIGHT('000' + CAST(sv.number AS VARCHAR(3)), 3)
+ ' = up.value FROM #Transposed t CROSS APPLY
( SELECT TOP 1 u.value FROM #unpivoted u WHERE u.field = t.field AND u.rn > '
+ CAST((sv.number-1)*#fieldCount AS VARCHAR(10)) + ' ORDER BY rn) up '
FROM [master].dbo.spt_values sv
WHERE sv.[type] = 'p'
AND sv.number BETWEEN 1 AND (SELECT COUNT(*) FROM #t)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '')
Exec(#SQL) /*Dynamically fill in values */
SELECT t.* FROM #Transposed t
OUTER APPLY (SELECT TOP 1 rn FROM #Unpivoted u WHERE u.field=t.field) up
ORDER BY up.rn ASC /* add a link to Unpivoted to fix the item order */
DROP TABLE #Unpivoted
DROP TABLE #Transposed
It does what you need in several steps
converts columns to rows with UNPIVOT. Watch that you have to CAST all the values to the exactly same type. Adds a row number to filter the rows in step 3.
creates a temp table with dynamic number of columns corresponding to the number of rows
fills in the columns names into rows into the dynamically created table
fills in values into the dynamically created table
Credits to this answer and this answer.
Of course the number of columns is limited here, so if you try to convert many rows into columns, you get:
Cannot create a row of size 8066 which is greater than the allowable
maximum row size of 8060.

Many SQL rows into one

I've got a stored procedure which joins a number of tables to produce a large resultset which is then returned to my application. The application in turn loops through the results and combines rows on a particular ID and chooses data per row to include in a new object. This is perhaps easiest to explain using an example:
Inspection, Desc, Value
1, Description1, 3
1, Description2, 2
1, Description3, 5
This is in code turned into
Inspection, Description1, Description2, Description3
1, 3, 2, 5
The point of this is to have one row per inspection item with item description as headers and value as the cell value for inspection row and header. This is then exported to Excel.
The question is: how do I do this in SQL Server, as in expanding my SP to return a lot fewer but "wider" rows with a lot more columns?
Another complication is that one inspection may have rows which another one lacks, in that case the solution is to add an empty value or a '-'.
P.S. This is using Sql Server 2012.
If you are using mssql 2005+. You can use a pivot like this:
Test data
DECLARE #tbl TABLE(Inspection INT, [Desc] VARCHAR(100),Value INT)
INSERT INTO #tbl
VALUES
(1,'Description1', 3),
(1,'Description2', 2),
(1,'Description3', 5)
Query
SELECT
*
FROM
(
SELECT
tbl.Inspection,
tbl.[Desc],
tbl.Value
FROM
#tbl AS tbl
) AS tbl
PIVOT
(
SUM(Value)
FOR [Desc] IN ([Description1],[Description2],[Description3])
)AS pvt
Result:
Inspection, Description1, Description2, Description3
1 3 2 5
Edit
As juharr said in the comment:
The resulting column names (values in the table) are when building the query. Which might require another initial query to get
Edit 2
If you are not using mssql 2005+. Or want to have and alternitive explanation. Please see the following query:
SELECT
tbl.Inspection,
SUM(CASE WHEN [Desc]='Description1' THEN tbl.Value ELSE 0 END) AS Description1,
SUM(CASE WHEN [Desc]='Description2' THEN tbl.Value ELSE 0 END) AS Description2,
SUM(CASE WHEN [Desc]='Description3' THEN tbl.Value ELSE 0 END) AS Description3
FROM
#tbl AS tbl
GROUP BY
tbl.Inspection
This do not requiere a pivot and can be use on most of RDMS out there
You should use Sql Server Pivot. It converts rows into columns. You can have an easiest start by this example.
If you'd like to do this dynamically, without having to know what all of the Desc values are, you can build your pivot query and use Exec() or Execute sp_executesql
DECLARE #Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX)
--Build your column headers based on Distinct Desc values
SELECT #Columns = COALESCE(#Columns + ',', '') + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your pivot query
SET #Sql = '
SELECT
*
FROM
tbl
PIVOT
(
MAX([Value])
FOR [Desc] IN (' + #Columns + ')
) p
'
EXEC(#Sql)
If you want - for null values, you'll need to create another variable to hold the conversion scripts for the Select part of your sql.
DECLARE #Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX),
#ColumnAliases NVARCHAR(MAX)
--Build your pivot columns based on Distinct Desc values
SELECT #Columns = COALESCE(#Columns + ',', '') + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your column headers, replacing NULL with -
SELECT #ColumnAliases = COALESCE(#ColumnAliases + ',', '')
+ 'COALESCE(CONVERT(VARCHAR,' + QUOTENAME([Desc]) + '),''-'') AS ' + QUOTENAME([Desc])
FROM (SELECT DISTINCT [Desc] FROM tbl) t
ORDER BY [Desc]
--Build your pivot query
SET #Sql = '
SELECT
Inspection,'
+ #ColumnAliases + '
FROM
tbl
PIVOT
(
MAX([Value])
FOR [Desc] IN (' + #Columns + ')
) p
'
EXEC(#Sql)

Categories

Resources