How to do insert and update in a stored procedure? - sql-server

I'm writing a stored procedure which is first doing an insert if the data does not exists. If the data exists, I'm updating the date column and inserting data. When I run the stored procedure, I get the following error.
incorrect syntax near ' ; '
I don't know what is going on or what I'm doing wrong... It seems like there's something wrong with my CTE, but I don't know for sure. Thank you in advance.
CREATE PROCEDURE [dbo].[spSCDTest] #SCD [dbo].[spSCDTest1] READONLY
AS
BEGIN
/****** SCD TYPE - 2 (retains the full history of values) ******/
/** DimUsers Insert New**/
CREATE NONCLUSTERED INDEX IX_DimUsers_userID
ON [dbo].[DimUsers] ([userID]);
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
INSERT INTO dbo.DimUsers
(
userID,
name,
location,
StartDate,
EndDate,
supervisor,
salary,
HashUsers
)
SELECT
cte.userID,
cte.name,
cte.location,
GETDATE() AS StartDate,
'12/31/9999' AS EndDate,
cte.supervisor,
cte.salary,
cte.HashUsers
FROM
DimCTE cte
WHERE not exists
(SELECT * FROM dbo.DimUsers DU WHERE DU.userID = cte.userID);
/** DimUsers Update Old**/
CREATE NONCLUSTERED INDEX IX_Enddate_serID
ON [dbo].[DimUsers] ([EndDate], [userID])
INCLUDE([HashUsers]);
DECLARE #NewEndDate datetime2;
SET #NewEndDate = GETDATE();
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
UPDATE DimUsers
SET
EndDate = #NewEndDate
FROM
DimUsers DU
INNER JOIN DimCTE cte ON DU.userID = cte.userID
WHERE
(
DU.EndDate = '12/31/9999' AND
cte.HashUsers <> du.HashUsers
);
/** DimUsers InsertOld Update**/
WITH DimCTE AS
(
SELECT * ,
HASHBYTES('SHA2_256',CONCAT(source.name,'|',source.location,'|',source.supervisor, '|',source.salary)) as [HashUsers]
FROM #SCD source
)
INSERT INTO dbo.DimUsers
(
userID,
name,
location,
StartDate,
EndDate,
supervisor,
salary,
HashUsers
)
SELECT
cte.userID,
cte.name,
cte.location,
#NewEndDate AS StartDate,
'12/31/9999' AS EndDate,
cte.supervisor,
cte.salary,
cte.HashUsers
FROM
DimCTE cte
INNER JOIN DimUsers DU ON DU.userID = cte.userID AND DU.EndDate = #NewEndDate;

Related

Trying to create a stored procedure with error capturing that would print error upon execution

I need help with creating a stored procedure. What I am trying to do is validate count between source and target table, upon executing stored procedure I need print that would say "there is miscount btwn source and target table. However I am not getting print message that I need, please see my code below and if you could let me know where error is in my code? FYI, this is my first attempt to automate some of my scripts as QA (for ETL). Please go easy on me :)
CREATE PROCEDURE ##accountDB_count
AS
BEGIN TRY
DROP TABLE IF EXISTS ##error_count;
CREATE TABLE ##error_count
(
[object] varchar(255),
source_count integer
);
WIT cte AS
(
SELECT
'Data Migration source count' as [object]
,count(distinct s.account_id) as count_all
FROM MariaDBMigration.infoarmor_secure.subscribers s
INNER JOIN MariaDBMigration.infoarmor_secure.subscribers_accounts sa ON s.account_id = sa.id
INNER JOIN MariaDBMigration.infoarmor_secure.subscribers_accounts_plan sap ON sa.account_type
= sap.id
INNER JOIN migration.dbo.map_subscriber_four_fields map on map.subscriber_id = s.id
WHERE s.customerid in (3444,3497,4662,4663,3958,3959,4549,4550,4655)
AND s.active = 1 --OR ( (DATEADD(DAY, 90, coalesce(canceled_date, getdate() ))) >
GETDATE() ) )
AND S.is_primary =1
)
,cte1 AS
(
SELECT 'ACCOUNT_target count' AS [object], COUNT(*) AS count_all
FROM account.dbo.account
)
,cte2 AS
(
SELECT * FROM cte
UNION
SELECT * FROM cte1
UNION
SELECT
'differance' AS [object],
(SELECT count_all FROM cte) - (SELECT count_all FROM cte1)
)
INSERT INTO ##error_count
SELECT * FROM CTE2
END TRY
BEGIN CATCH
DECLARE #COUNT_ALL INT = 0;
WHILE #COUNT_ALL != (SELECT * FROM ##error_count WHERE [object] = 'differance')
begin
PRINT 'MISSCOUNT'
end
END CATCH

How to get cumulative record In SQL Server?

I have some data in SQL Server in below format.
declare #statement table
(
acctno int,
statDate date,
tod int,
lastDate date
)
insert into #statement select 123,'2018-02-12',567,'2018-01-12'
insert into #statement select 123,'2018-03-12',580,'2018-02-12'
insert into #statement select 123,'2018-04-12',567,'2018-03-12'
--select * from #statement
declare #txn table
(
acct int,
txndate date,
amount int
)
insert into #txn select 123,'2018-02-11',400
insert into #txn select 123,'2018-02-18',400
insert into #txn select 123,'2018-02-25',400
insert into #txn select 123,'2018-03-11',400
insert into #txn select 123,'2018-03-25',400
Result of the both tables similar like below.
]1
Now I want the result as shown here:
and I am trying to get it with this query:
;with cte as
(
select
acctno, statDate, tod, txndate, amount, lastDate
from
#statement
inner join
#txn on acctno = acct
)
select *
from #txn t
left join cte on acct = acctno
and t.txndate between statDate and lastDate
But the result is not being returned as expected - please help me get the desired result.
I think that you can do this more simply
select s.acctno,statDate,tod,txndate,amount,lastDate
from #txn t
Inner join #statement s
On s.acctno = t.acct
And t.txndate Between s.lastDate and s.startDate
You may need to change the BETWEEN to a “<“ for the startDate comparison.
This is a clasical DKNF join :
WITH TD AS(
SELECT T1.acctno, T1.statDate AS StartDate, T1.tod, COALESCE(MAX(T2.statDate), '1-01-01') AS BeforeDate
FROM #statement AS T1
LEFT OUTER JOIN #statement AS T2
ON T1.acctno = T2.acctno AND T1.statDate < T2.statDate
GROUP BY T1.acctno, T1.statDate, T1.tod
)
SELECT acctno, StartDate, tod, txndate, amount
FROM TD
JOIN #txn AS t
ON TD.acctno = t.acct AND txndate <= StartDate AND txndate > BeforeDate

Column name or number of supplied values does not match table definition in a stored procedure

I'm trying to execute this stored procedure, the query throws an error:
Column name or number of supplied value does not match table definition.
What I would like to get from this stored procedure is one line of all columns.
Please help to solve the error.
ALTER PROCEDURE `uspx_MUL_Status`
#OrderNumber VARCHAR(20),
#SelectQty BIT,
#SelectDate DATE,
#oKey INT
AS
BEGIN
CREATE TABLE #TempStatus
(
OrderNum VARCHAR (20),
`QtéCom` SMALLINT,
`DateCom` DATE,
`QtéSelec` SMALLINT,
`DateSelec` DATE,
`QtéProd` SMALLINT,
DateProd DATE
)
INSERT INTO #TempStatus
-- Quantité commandée--
SELECT OrderNumber, SUM(`od.Quantity`), MAX(CreateDate)
FROM OrderDetail `od`
JOIN Orders o ON od.oKey =o.oKey
WHERE OrderNumber = #OrderNumber
GROUP BY CreateDate, OrderNumber
-- Quantité sélectionnée--
SET #SelectQty = 0
SET #SelectDate = NULL
SELECT #SelectQty = SUM(`sd.Quantity`), #SelectDate = MAX(`ReleaseDate`)
FROM ScheduleDetail `sd`
JOIN Orders o ON o.oKey =`sd.oKey`
JOIN Schedules s ON `sd.SchedID` = `s.SchedID` AND o.LocationID = s.LocationID
WHERE o.oKey = #oKey
GROUP BY ReleaseDate
UPDATE #TempStatus
SET `QtéSelec` = #SelectQty, `DateSelec` = #SelectDate
-- Quantité produite--
SET #SelectQty = 0
SET #SelectDate = NULL
SELECT
#SelectQty = SUM(`od.CompleteQuantity`),
#SelectDate = MAX(`o.CompleteDate`)
FROM OrderDetail `od`
JOIN Orders o ON o.oKey = od.oKey
WHERE o.oKey = #oKey
GROUP BY CompleteDate
UPDATE #TempStatus
SET `QtéProd` = #SelectQty, `DateProd` = #SelectDate
SELECT * FROM #TempStatus
END
EXEC `uspx_MUL_Status` #OrderNumber='TC19227', #SelectQty=0, #SelectDate=NULL, #oKey=42334
Specify the columns on this line:
INSERT INTO #TempStatus
Like this:
INSERT INTO #TempStatus (Column1, Column2, Column3, etc)

how to change effectively the In clause in SQL

we have a employee_master table and a Report_Filter Table, the Report_Filter contains different typs of filter the user enters for eg. status, employee code, nationaality etc. and this report_filter contains the user Information also. The table structure is like this Report_Filter( User_Id, Report_TYpe, Report_Code ) all are character fields. based on the users input the table will have values like
( 'User_1', 'STATUS', '01' )
( 'user_1', 'STATUS', '02' )
( 'User_1', 'EMP_CODE', 'ABC' )
( 'User_1', 'NATIONALITY', 'ALL' ) -- All means he want to see all the nationalities
now currently we are writing the query like this
Select Emp_code, Emp_Name, status, nationlity
From Empolyee_Master m
Where
('All' in ( select report_code from Report_Filter where user_id = #user_id and report_type='STATUS') or m.STATUS in ( select report_code from Report_Filter where user_id = #user_id and report_type='STATUS') ) and
or m.CATEGORY in ( select report_code from Report_Filter where user_id = #user_id and report_type='NATIONALITY') ) and
or m.emp_code in ( select report_code from Report_Filter where user_id = #user_id and report_type='EMP_CODE') )
there are other conditions also we are using, the problem is its take too much time because of the In clauses. how can we effectively change this code for improving performance
we are using MSSQL 2014
Instead of retrieving all values and then seeing if your value is part of it, you should filter by your value. Try if this helps (just one example):
replace
WHERE 'ALL' in (
select report_code from Report_Filter
where user_id = #user_id and report_type='STATUS'
)
with
WHERE EXISTS (
select 1 from Report_Filter
where user_id = #user_id and report_type='STATUS'
and report_code = 'ALL'
)
Now it would also help to include column report_code in an INDEX (you are using INDEXes, I hope?)
Update - to skip filtering in case of 'ALL', that can be done like this:
DECLARE #statusFilter VARCHAR(20) = ... -- 'ALL' or other value
SELECT ...
WHERE #statusFilter = 'ALL'
OR EXISTS (
select 1 from Report_Filter
where user_id = #user_id and report_type='STATUS'
and report_code = #statusFilter
)
You can try to do the filtering in advance:
(For your next question: Such a mockup should be done by you)
DECLARE #ReportFilter TABLE([user_id] VARCHAR(100),report_type VARCHAR(100),report_code VARCHAR(100));
INSERT INTO #ReportFilter VALUES
( 'User_1', 'STATUS', '01' )
,( 'user_1', 'STATUS', '02' )
,( 'User_1', 'EMP_CODE', 'ABC' )
,( 'User_1', 'NATIONALITY', 'ALL' );
DECLARE #Employee_Master TABLE(Emp_Code VARCHAR(100),Emp_Name VARCHAR(100), [status] VARCHAR(100), nationality VARCHAR(100));
INSERT INTO #Employee_Master VALUES
('ABC','test1','01','USA')
,('DEF','test2','99','GB')
,('ABC','test3','02','DE')
,('XYZ','test4','01','FRA');
--This is part of your query
DECLARE #user_id VARCHAR(100)='User_1';
WITH filterSTATUS AS
(
SELECT * FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='STATUS'
AND NOT EXISTS(SELECT 1 FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='STATUS' AND report_code='ALL')
)
,
filterEMPCODE AS
(
SELECT * FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='EMP_CODE'
AND NOT EXISTS(SELECT 1 FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='EMP_CODE' AND report_code='ALL')
)
,filterNATIONALITY AS
(
SELECT * FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='NATIONALITY'
AND NOT EXISTS(SELECT 1 FROM #ReportFilter WHERE [user_id]=#user_id AND report_type='NATIONALITY' AND report_code='ALL')
)
SELECT *
FROM #Employee_Master AS em
WHERE (SELECT COUNT(*) FROM filterSTATUS)=0 OR em.[status] IN (SELECT x.report_code FROM filterSTATUS AS x)
AND (SELECT COUNT(*) FROM filterEMPCODE)=0 OR em.Emp_Code IN (SELECT x.report_code FROM filterEMPCODE AS x)
AND (SELECT COUNT(*) FROM filterNATIONALITY)=0 OR em.nationality IN (SELECT x.report_code FROM filterNATIONALITY AS x);
For the give set this returns
Emp_Code Emp_Name status nationality
ABC test1 01 USA
ABC test3 02 DE

Conditional FROM clause

My coworkers are using entity framework and have got 3 (schematically) identical databases. These databases are updated and modified by their application. I am writing another, separate application to gather information about their application.
I am trying to use stored procedures but having trouble. It seems I must have three copies of my query in every stored procedure (one for each database) and JOIN them all at the end. I don't want to have three copies of every query with only the table name changed. Can I specify using a parameter, CASE statement, or something else the table I use in my FROM Clause?
Two options: dynamic SQL, or a UNION ALL statement.
SELECT columnlist
FROM TABLE1
WHERE #param = 'Table1'
UNION ALL
SELECT columnlist
FROM TABLE2
WHERE #param = 'Table2'
UNION ALL
SELECT columnlist
FROM TABLE3
WHERE #param = 'Table3'
Since you are working with stored procedures, you can pass the table name from which you want to query as parameter like
create procedure sp_test
#tab_name varchar(10)
as
begin
if(#tab_name = 'Table1')
select * from Table1
else if (#tab_name = 'Table2')
select * from Table2
else
select * from Table3
end
Then run your SP like
exec sp_test 'Table1'
EDIT:
As per your comment you want to change the DB name in your query. So in DB.HistoryOne JOIN DB.HistoryTwo you want to change the DB to DB1. You can do it like below in a procedure
create procedure sp_DB_change
#DBname varchar(10)
as
begin
declare #sql varchar(200);
set #sql = 'SELECT AVG(DATEDIFF(s, StartDate, OtherStartDate)) AS time1 ,
CAST(OtherStartDate AS Date) AS [Date]
FROM DB.HistoryOne
JOIN DB.HistoryTwo ON HistoryOne.Id = HistoryTwo.Id
WHERE StartDate IS NOT NULL
AND OtherStartDate IS NOT NULL
AND OtherStartDate > DATEADD(d, -7, GETDATE())
GROUP BY CAST(OtherStartDate AS DATE)';
select #sql = REPLACE(#sql,'DB',#newdb)
exec (#sql)
end
Then run your SP like
exec sp_DB_change 'testDB'
So your original query
SELECT AVG(DATEDIFF(s, StartDate, OtherStartDate)) AS time1 ,
CAST(OtherStartDate AS Date) AS [Date]
FROM DB.HistoryOne
JOIN DB.HistoryTwo ON HistoryOne.Id = HistoryTwo.Id
WHERE StartDate IS NOT NULL
AND OtherStartDate IS NOT NULL
AND OtherStartDate > DATEADD(d, -7, GETDATE())
GROUP BY CAST(OtherStartDate AS DATE)
Will be converted to
SELECT AVG(DATEDIFF(s, StartDate, OtherStartDate)) AS time1 ,
CAST(OtherStartDate AS Date) AS [Date]
FROM testDB.HistoryOne
JOIN testDB.HistoryTwo ON HistoryOne.Id = HistoryTwo.Id
WHERE StartDate IS NOT NULL
AND OtherStartDate IS NOT NULL
AND OtherStartDate > DATEADD(d, -7, GETDATE())
GROUP BY CAST(OtherStartDate AS DATE)

Resources