SQL INSERT with conditional statement IF THEN ELSE - sql-server

I am trying to MERGE values from one table to another. One of the values is a conditional value, but it looks like I am not getting the syntax correctly. Initially, I was using an IF-THEN-ELSE statement but was advise to use a CASE statement instead.
Here is the gist the syntax that is failing:
CREATE PROCEDURE EmployeeMerge
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO Employee AS t1
USING
(SELECT
EmployeeName,
Zip,
UpdateDate
FROM table2) AS t2
ON (t1.EmployeeID = t2.EmployeeID)
WHEN MATCHED AND t2.UpdatedDate > t1.UpdatedDate THEN
UPDATE
SET
t1.EmployeeName = s.EmployeeName,
t1.Zip =
(CASE
WHEN t2.ZipExt IS NULL OR t2.ZipExt = '' THEN t2.Zip
ELSE (t2.Zip + '-' + t2.ZipExt)
END),
t1.UpdatedDate = t2.UpdateDate
WHEN NOT MATCHED THEN
INSERT (EmployeeName,
Zip,
ModDate)
VALUES
(t2.Name,
(CASE
WHEN t2.ZipExt IS NULL OR t2.ZipExt = '' THEN t2.Zip
ELSE (t2.Zip + '-' + t2.Zip_Ext)
END),
t2.UpdatedDate)
OUTPUT
deleted.*,
$action,
inserted.*
END; **-- A MERGE statement must be terminated by a semi-colon (;)**
GO
This MERGE statement works just fine if I do not implement the condition, i.e. simply set the t1.Zip = t2.Zip, but of course, this is avoiding the t2.ZipExt field.

A MERGE statement must be terminated by a semi-colon (;)
You haven't terminated the MERGE with a semicolon. You have terminated BEGIN-END. Move the semicolon.

I never really cared for the merge command. There are times where I can see using it, but for the most part, it's more complicated than I like my SQL.
UPDATE e
SET e.EmployeeName=t1.EmployeeName
, e.Zip=CASE
WHEN t1.ZipExt IS NULL OR t1.ZipExt = '' THEN t1.Zip
ELSE (t1.Zip + '-' + t1.ZipExt)
END
, e.UpdatedDate=t1.UpdatedDate
FROM Employee e
INNER JOIN Table t1 ON e.EmployeeID = t1.EmployeeID
WHERE t1.UpdatedDate > e.UpdatedDate
INSERT INTO Employee (EmployeeName,Zip,UpdatedDate)
SELECT
t1.EmployeeName
, t1.Zip=CASE
WHEN t1.ZipExt IS NULL OR t1.ZipExt = '' THEN t1.Zip
ELSE (t1.Zip + '-' + t1.ZipExt)
END
, t1.UpdatedDate
FROM Table t1
LEFT JOIN Employee e ON e.EmployeeID = t1.EmployeeID
WHERE e.EmployeeID IS NULL

Related

If Statement in SQL From Clause

I'm trying to perform an if statement that needs to be done within the From clause of my query. However when I try to do so, I get this error
Incorrect syntax near the keyword 'THEN'.
The query I'm trying to use is the following:
SELECT *
FROM
--a few tables with joins
IF (#a IS NULL OR #a <> '') THEN
--perform a few more joins
WHERE
--rest of query
Is it not possible to perform a case or if statement from the from clause?
After realising I can't use a IF Statement and Case would be more appropriate, I've read up and this can only be done dynamically and not from SQL itself.
You can't do this on a fundamental level. When you write a query, you already know what data it will return and what tables are needed to get that data.
Now, you can do some switchng between tables in a join by using outer joins and statements like ISNULL() and COALESCE() to see if the joined table actually has the data we're looking for.
The joins could loook like this:
declare #checkthis int
select #checkthis = (whatever, resulting in a 1 or a 0)
select *
from tbl_a as a
left outer join tbl_b as b -- tbl_b is optional if #checkthis is 1, else ignore it
on a.b_foreign_key = b.primary_key and #checkthis = 1
Depending on your joins, you can do something like this...
DECLARE #Join AS BIT
SET #Join = 1 --Performs inner join
SET #Join = 0 --ignores join
SELECT *
FROM Table1 a
LEFT JOIN Table2 b
ON a.Id = b.Id
WHERE
((#Join = 0) OR (#Join = 1 AND b.Id IS NOT NULL))
The IF statement in TSQL has the following syntax:
IF [Condition] --NO 'THEN' keyword needed
BEGIN
--myquery
END
ELSE IF [2nd Condition]
BEGIN
--myquery
END
ELSE
BEGIN
--myquery
END
[Condition] can be everything that gives you a TRUE output like
IF DAY(GETDATE()) = 7
BEGIN
PRINT 'IT IS TRUE'
END
ELSE
BEGIN
PRINT 'IT IS FALSE'
END
For your specific problem, you can use CASE statement, in a WHERE clause, like this:
SELECT *
FROM MYTABLE T
INNER JOIN MYTABLE2 T2 ON T2.ID = T1.ID
WHERE T.MYCOLLUMN = CASE
WHEN T.MYCOLUMN2 = 0 THEN 'FIRST'
WHEN T.MYCOLUMN2 = 1 THEN 'SECOND'
ELSE T2.MYCOLUMN
END

sql ssrs how to match variable to table parameter

I have a report that requires a parameter which may have one value, or a collection of values (jurisdictions assigned to a district office). I can't figure out how to ask sql if a particular value (a.jurisdiction) matched to a value contained in a parameter set up as a table. I have the following code:
DECLARE #District INT = 1614 --Richmond D1
DECLARE #StartDate DATETIME = '20160101'
DECLARE #EndDate DATETIME = '20160731'
DECLARE #Jurisdiction TABLE(Location INT) --= 1223 --Richmond City --multiselect?
IF #District = 1614 --Richmond District 1
INSERT INTO #Jurisdiction Values (1223); --Richmond City
IF #District = 1632 --Newport News District 19
INSERT INTO #Jurisdiction Values (1203); --Newport News
IF #District = 1642 --Fairfax District 29
INSERT INTO #Jurisdiction Values (2568) --Fairfax City
,(1154) ,(1140) ,(1178) ,(1243)
SELECT b.OffenderId
, b.Sex
, b.CurrentLocationId
, b.MasterTermId
, b.ReleaseDate
, b.Jurisdiction
, b.HomePlanAddress
FROM (SELECT DISTINCT o.OffenderId
, o.CurrentLocationId
, CASE WHEN o.GenderId = 12 THEN 'M'
WHEN o.GenderId = 13 THEN 'F'
ELSE 'Unknown' END AS Sex
, mt.MasterTermId
, t.TermId
, CASE WHEN t.GtrdApprovedDate IS NULL AND
t.MprdApprovedDate IS NULL THEN '19000101'
WHEN t.GtrdApprovedDate IS NULL THEN t.MprdApprovedDate
WHEN t.MprdApprovedDate IS NULL THEN t.GtrdApprovedDate
WHEN t.MprdApprovedDate < t.GtrdApprovedDate THEN
t.MprdApprovedDate
ELSE t.GtrdApprovedDate END AS ReleaseDate
, j.HomePlanAddress
, j.Jurisdiction
FROM ind.Offender AS o
INNER JOIN (SELECT oa.OffenderId
, oa.AddressId
, LTRIM(COALESCE(CAST(a.StreetNumber AS
VARCHAR(10)),' ') + COALESCE(a.StreetNumberSuffix
+ ' ',' '
+ COALESCE(a.StreetName + ',','') + COALESCE(' '
+ a.AppartmentNumber + ',','')
+ l.LocationName + ',' + 'VA ' + COALESCE
(a.ZipCode,'')) AS HomePlanAddress
, j.LocationName AS Jurisdiction
FROM ind.Offender_Address AS oa
INNER JOIN ref.Address AS a ON oa.AddressId =
a.AddressId
LEFT JOIN ref.Location AS l ON a.CountyId = l.LocationId
INNER JOIN ref.Location AS j ON a.JurisdictionId = j.LocationId
WHERE a.StateId = 1047
AND EXISTS (SELECT a.JurisdictionId FROM #Jurisdiction)
--AND a.JurisdictionId IN (#Jurisdiction) --
AND oa.AddressTypeId = 5 --Proposed
AND oa.EndDate IS NULL) AS j ON o.OffenderId = j.OffenderId
INNER JOIN scl.MasterTerm AS mt ON o.OffenderId = mt.OffenderId
LEFT JOIN scl.Term AS t ON mt.MasterTermId = t.MasterTermId
WHERE o.CurrentLocationId IS NOT NULL
AND t.TermStatusId <> 631) AS b --Inactive
WHERE b.ReleaseDate BETWEEN #StartDate AND #EndDate
I've tried to find solutions, but most of them refer to using stored procedures, which I can't use in our environment. I tried the EXISTS option on one answer I found, but it gives me all locations, not just the ones in the parameter. Any suggestions?
The reference to the answer SSRS Multiple Value parameter filter based on dataset doesn't seem to address the fact that the District parameter has no one-on-one match to the values used for Jurisdiction. But it gives me something to work on and play around with.
I don't know why
AND a.JurisdictionId IN (#Jurisdiction)
doesn't work for you. As far as I can tell it should.
You can try adding the Filter to the SSRS dataset instead of inside the query. Choose your Jurisdiction for the Expression and your Jurisdiction Parameter as the value.

Convert money datatype to 3 decimal places

I am trying to show my PT.TotalAmount(money) field in decimal format upto 3 decimal places. I tried using
CAST(ROUND(123.4567, 3) AS MONEY)
But I get error:
An object or column name is missing or empty. For SELECT INTO
statements, verify each column has a name. For other statements, look
for empty alias names. Aliases defined as "" or [] are not allowed.
Change the alias to a valid name.
Here is my SP:
Select PT.[ID] 'TransactionID', PT.BatchNumber, PT.SequenceNumber, PT.TransactionDate,
PT.TerminalID ,CAST(ROUND(PT.TotalAmount, 2) AS MONEY), PT.TransactionTypeID, TT.TransactionType,
PT.PAN 'EmbossLine',PT.PreBalanceAmount, PT.PostBalanceAmount, RefTxnID,
SettlementDate,PaidCash, CreditAmount, DiscountAmount,
RefPAN, PT.Remarks, ' ' + CashierCard as 'SupervisorCard',St.StoreID
into #Temp
from POS_Transactions PT inner join TransactionType TT on TT.TransactionTypeID = PT.TransactionTypeID
inner join Staff St on St.CardNumber=PT.CashierCard
where
PT.[ID] not in (Select distinct isnull(TransactionID,0) from Testcards)
and (PT.TransactionDate >= #DateFrom)
and (PT.TransactionDate < #DateTo)
and (PT.TransactionTypeID = #TransactionTypeID or #TransactionTypeID = -999)
select T.*, ' '+ C.EmbossLine as 'EmbossLine', ' '+ C.EmbossLine as 'EmbossLine1',
isnull(C.FirstName,'') +' '+ isnull(C.LastName,'') 'EmbossName',C.FirstName,C.LastName,City.CityName,Country.CountryName,Country.CurrencyName, PM.MerchantID , PM.MerchantName1, C.AccountNumber, C.VehicleNumber
from #Temp T
inner join Card C on C.EmbossLine= T.EmbossLine
inner join Terminal on Terminal.TerminalID = T.TerminalID
inner join Merchant PM on PM.MerchantID = Terminal.MerchantID
inner join City on City.CityID = PM.CityID
inner join Country on Country.CountryID = PM.CountryID
where C.Status <>'E3'
and C.CardID not in (Select distinct isnull(CardID,0) from Testcards)
and (PM.MerchantID =#MerchantID or #MerchantID='-999')
and (C.EmbossLine like '%'+#EmbossLine+'%' or #EmbossLine like '-999')
and (C.FirstName like '%'+#FirstName+'%' or #FirstName like '-999')
and (C.LastName like '%'+#LastName+'%' or #LastName like '-999')
and (PM.CountryID = #CountryID or #CountryID ='-999')
and(PM.CityID = #CityID or #CityID ='-999')
order by T.TransactionDate, MerchantName1, T.BatchNumber, T.SequenceNumber
drop table #Temp
Why am I getting this error? Whats wrong in conversion? When I simply write PT.TotalAmount in my Select statement, the query is completed successfully
Just add any alias name for CAST(ROUND(PT.TotalAmount, 2) AS MONEY) as roundedamont(whatever column name you want) in your sql query.
Select * into statement require each column have distinct name
Select PT.[ID] 'TransactionID', PT.BatchNumber, PT.SequenceNumber, PT.TransactionDate,
PT.TerminalID ,CAST(ROUND(PT.TotalAmount, 2) AS MONEY)<----Give Alias HERE

Repeating same SQL

I am writing a CASE statement in my SQL Server Stored Procedure. There I am repeeating a same long SQL statements every time for 11 CASEs. Should I put the SQL Statement in CASE condition in a another Stored Procedure? What could be the best approach?
CASE (SELECT ..................)
THEN 'SELCET a.field'
ELSE
''SELECT vlaues'
END
as 'Coulmn1 '
CASE (SELECT ..................)
THEN 'SELCET vaues'
ELSE
''SELECT vlaues'
END
as 'Coulmn1 '
You might want to do something like
SELECT
CASE (your select statement which retuns one value)
WHEN 'option1' THEN 'value2return1'
WHEN 'option2' THEN 'value2return2'
WHEN 'option3' THEN 'value2return3'
...
ELSE 'defaultValue'
END
Use common table expressions link.
WITH CTE (ColA)
AS
(
Select ColA From Table
)
SELECT ColA
FROM CTE
Use a CTE. In the future it would help if you gave us a slightly better example of your code however.
WITH RepeateSelect AS (SELECT ..................)
.....
.....
CASE (SELECT * FROM RepeateSelect)
THEN 'SELCET a.field'
ELSE
'SELECT vlaues'
END
as 'Coulmn1 '
CASE (SELECT * FROM RepeateSelect)
THEN 'SELCET vaues'
ELSE
''SELECT vlaues'
END
as 'Coulmn1 '
Try using the repeated query once thusly:
select A.C1, X.C2, X.C3
from TableA as A inner join
( select B.AlmondJoy,
case when B.YN > 7 then 'Yes' else 'No' end as C2,
case when C.UD in ( -1, 1 ) then 'Up' else 'Down' end as C3
from TableB as B inner join
TableC as C on C.Id = B.Id
) as X on X.AlmondJoy = A.Zagnut

tsql - While Loop issue using temp table

Our DBA has changed a function to be a procedure, so I am amending some of my procedures to cater for this. I've come across a problem with this in one of my procedures where I have a while loop.
I populate my temp table from the new procedure (#DGContol), and then have the following while loop:
SELECT #MinRcd = MIN(RcdNum) FROM #PortfolioDisclosure
SELECT #MaxRcd = MAX(RcdNum) FROM #PortfolioDisclosure
SET #RcdNum = #MinRcd
WHILE #RcdNum <= #MaxRcd
BEGIN
-- Temporarily assign values to variables
SELECT
#PortfolioGroup = PortfolioCode
, #EndDateTime = MaxPositionDate_DetailedDisclosure
FROM #PortfolioDisclosure
WHERE RcdNum = #RcdNum
INSERT INTO #PositionsTable
SELECT
fi.ID_ISIN AS [Fund_ISIN]
, RTRIM(a.acct_id) AS [Internal_Portfolio_Code]
, a.acct_desc AS [Portfolio/Fund_Name]
, CONVERT(CHAR(11),p.as_of_tms,103) AS [Portfolio_Date]
, a.alt_curr_cde AS [Portfolio_Base_Ccy]
, i.iss_desc AS [Security_Description]
, RTRIM(i.pref_iss_id) AS [Security_ID SEDOL/Internal]
, RTRIM(ia.iss_id) AS [Security_ID ISIN]
, i.denom_curr_cde AS [Denomination_Ccy]
, SUM(p.valval_alt_cmb_amt) OVER (PARTITION BY RTRIM(a.acct_id))
AS [Total_Fund_Value]
, p.orig_quantity AS [Shares/Par_Value]
, p.valval_alt_cmb_amt AS [Market_Value]
, p.fld5_rte AS [Pct_of_NAV]
, SUM(CASE WHEN i.issue_cls1_cde = '010' THEN p.valval_alt_cmb_amt ELSE 0 END) OVER (PARTITION BY a.acct_id)
AS [Cash/Cash_Equivalents]
, i.inc_proj_cmb_rte AS [Coupon_Rate]
, CONVERT(CHAR(11),i.mat_exp_dte,103) AS [Maturity_Date]
FROM dw_position_dg AS p
INNER JOIN #DGControl AS dgc -- [M]onthly, [M]ost recent position
ON dgc.DataGrpCtlNum = p.data_grp_ctl_num
INNER JOIN dw_ivw_acct AS a WITH (NOLOCK)
ON a.acct_id = p.acct_id
INNER JOIN dw_issue_dg AS i WITH (NOLOCK)
ON i.instr_id = p.instr_id
LEFT OUTER JOIN dw_issue_alt_id AS ia WITH (NOLOCK)
ON ia.instr_id = i.instr_id
AND ia.id_ctxt_typ = 'ISIN'
INNER JOIN #PortfolioDisclosure AS fi
ON fi.PortfolioCode = p.acct_id
and fi.MaxPositionDate_DetailedDisclosure >= p.as_of_tms
WHERE RTRIM(a.acct_id) NOT IN ( SELECT xref.internal_value FROM dbo.DP_CrossReference as xref
WHERE xref.Codeset_type_id = 10401
AND xref.Originator_id = 'DataVendorPortfolioExclusion')
-- Clear down variable values
SET #PortfolioGroup = NULL
--SET #StartDateTime = NULL
SET #EndDateTime = NULL
-- Move to next record
SET #RcdNum = #RcdNum + 1
END -- END WHILE LOOP
However this returns lots of duplicate records. If I replace the temp table #DGControl with the original function then I get the correct number of records.
I don't really know what the issue would be or how I could re code this while loop so that using the table #DGControl I get the correct number of records. Can anyone help?
Have you compared the output of SELECT * FROM OldFunction(args..) with EXEC NewStoredProcedure args...? If so, does the data returned look the same or has the duplication crept in when the DBA refactored the function to a proc.
If so you may need to de dupe the output from the sp first then run it through your remaining code. In short, if you are using the same arguments for both but they give you different results then you'll need to go back to the DBA.
You aren't using either of your local variables (#PortfolioGroup, #EndDateTime) in this code. It is just inserting the same record set N number of times. Also, I think you can write this as a single select query without using temp tables or while loops and it will make it less confusing.
Thank you for your feedback. i worked out the issue. My code looks like the following now:
BEGIN
SELECT #MinRcd = MIN(RcdNum) FROM #PortfolioDisclosure
SELECT #MaxRcd = MAX(RcdNum) FROM #PortfolioDisclosure
SET #RcdNum = #MinRcd
WHILE #RcdNum <= #MaxRcd
BEGIN
-- Temporarily assign values to variables
SELECT
#PortfolioGroup = PortfolioCode
, #EndDateTime = MaxPositionDate_DetailedDisclosure
FROM #PortfolioDisclosure
WHERE RcdNum = #RcdNum
-- Insert DGControl record into table based on the MaxPositionDate_DetailedDisclosure from Portfolio Disclosure function
INSERT INTO #DGControl
EXEC InfoPortal..usp_Generic_DGControl '', '', #PortfolioGroup, '1', #EndDateTime, #EndDateTime, #PeriodType, 'M', 'POSITION' -- [M]onthly, [M]ost recent position
-- Insert into #PositionsTable
INSERT INTO #PositionsTable
SELECT
fi.ID_ISIN AS [Fund_ISIN]
, RTRIM(a.acct_id) AS [Internal_Portfolio_Code]
, a.acct_desc AS [Portfolio/Fund_Name]
, CONVERT(CHAR(11),p.as_of_tms,103) AS [Portfolio_Date]
, a.alt_curr_cde AS [Portfolio_Base_Ccy]
, i.iss_desc AS [Security_Description]
, RTRIM(i.pref_iss_id) AS [Security_ID SEDOL/Internal]
, RTRIM(ia.iss_id) AS [Security_ID ISIN]
, i.denom_curr_cde AS [Denomination_Ccy]
, SUM(p.valval_alt_cmb_amt) OVER (PARTITION BY RTRIM(a.acct_id))
AS [Total_Fund_Value]
, p.orig_quantity AS [Shares/Par_Value]
, p.valval_alt_cmb_amt AS [Market_Value]
, p.fld5_rte AS [Pct_of_NAV]
, SUM(CASE WHEN i.issue_cls1_cde = '010' THEN p.valval_alt_cmb_amt ELSE 0 END) OVER (PARTITION BY a.acct_id)
AS [Cash/Cash_Equivalents]
, i.inc_proj_cmb_rte AS [Coupon_Rate]
, CONVERT(CHAR(11),i.mat_exp_dte,103) AS [Maturity_Date]
FROM dw_position_dg AS p
INNER JOIN #DGControl AS dgc
ON dgc.DataGrpCtlNum = p.data_grp_ctl_num
INNER JOIN dw_ivw_acct AS a WITH (NOLOCK)
ON a.acct_id = p.acct_id
INNER JOIN dw_issue_dg AS i WITH (NOLOCK)
ON i.instr_id = p.instr_id
LEFT OUTER JOIN dw_issue_alt_id AS ia WITH (NOLOCK)
ON ia.instr_id = i.instr_id
AND ia.id_ctxt_typ = 'ISIN'
INNER JOIN #PortfolioDisclosure AS fi
ON fi.PortfolioCode = p.acct_id
-- Clear down variable values
SET #PortfolioGroup = NULL
--SET #StartDateTime = NULL
SET #EndDateTime = NULL
-- Clear down #DGControl table to allow new record to be inserted
DELETE FROM #DGControl
-- Move to next record
SET #RcdNum = #RcdNum + 1
END -- END WHILE LOOP
Adding the execution of the stored proc usp_Generic_DGControl at the beginning and then clearing it down after each loop stopped the duplication of the records.

Resources