SQL not hard case statement - sql

I'm working on an issue with a stored procedure. I have the following:
SELECT #message = 'ID' + CAST(CASE WHEN #StoreID = 0 THEN 'BK'
WHEN #StoreID = 1 THEN 'MK'
END AS VARCHAR (50)) + char(13)
This sends an e-mail that says: ID: 'MK' or ID:'BK'.
Currently i'm hard-coding the case statement, but I need to pull the strings 'BK' 'MK' from a different table all together.
The #StoreID is from the Store_Orders table. The names are from the Store table.
One way to get this I tried was doing this:
SELECT #message = 'ID' + StoreName from db.Store where StoreName = StoreID and StoreID = #StoreID
When I execute the code, it finds the correct store, but says that
Conversion failed when converting the varchar value 'MK' to data type
int.
But I don't want to convert 'MK' I want to display 'MK' by finding it via the #StoreID.

Are you looking for something like this:
SELECT CONCAT('ID: ' , CASE WHEN s.StoreID = 0
THEN (select '(''' + colname + ''')'
from othertable ot where ot.colname = s.colname)
WHEN s.StoreID = 1
THEN (select '(''' + colname + ''')'
from othertable ot where ot.colname = s.colname)
END) AS 'Message'
FROM Store_Orders s

Related

Disregard certain lines if false

I wrote this query and it is designed to send an email to a customer with info in a database. I would like it to do a check for any values that return as 0 and not send them in the #message. I imagine I'll need an if statement but I haven't been able to figure out how to make it work. Any help is appreciated.
Query:
select #AssignedCount = (select COUNT(*)
FROM event
where status_name = 'ASSIGNED' AND primary_unitid = NULL
OR status_name = 'ASSIGNED' AND primary_unitid = '')
select #UnitResource = (select COUNT (*)
from unit_resources
where unit_seqnum NOT IN (select unit_seqnum from unit))
select #UnitEmployee = (select COUNT (*)
from unit_employees
where unit_seqnum NOT IN (select unit_seqnum from unit))
select #LoggedOff = (select COUNT(*)
from unit
where status_name = 'LOGGED_OFF')
select #Duplicates = (SELECT ISNULL(
(select COUNT(*)
from unit
group by unitid
having COUNT(*) > 1), 0))
select #message =
'Status Report' +
' Events in assigned status with no primary unit: '
+ REPLACE((str(#AssignedCount)),' ','') +
' Un-linked unit resource table rows: '
+ REPLACE((str(#UnitResource)),' ','') +
' Un-linked Unit resource table rows: '
+ REPLACE((str(#UnitEmployee)),' ','') +
' Units with a status of Logged Off: '
+ REPLACE((str(#LoggedOff)),' ','') +
' Duplicate Units: '
+ REPLACE((str(#Duplicates)),' ','')`
You will have to use if statements to dynamically build the string:
-- setting to blank; otherwise, the string would be null
set #message = ''
-- dynamically building #message with if statements
if #AssignedCount > 0
set #message = 'Status Report' +
' Events in assigned status with no primary unit: '
+ REPLACE((str(#AssignedCount)),' ','')
if #UnitResource > 0
set #message = #message + ' Un-linked unit resource table rows: '
+ REPLACE((str(#UnitResource)),' ','')
if #UnitEmployee > 0
set #message = #message + ' Un-linked Unit resource table rows: '
+ REPLACE((str(#UnitEmployee)),' ','')
if #LoggedOff > 0
set #message = #message + ' Units with a status of Logged Off: '
+ REPLACE((str(#LoggedOff)),' ','')
if #Duplicates > 0
set #message = #message + ' Duplicate Units: '
+ REPLACE((str(#Duplicates)),' ','')
-- removing leading space from #message if AssignedCount is 0
set #message = ltrim(#message)
Personally, actually, rather than a bunch of IF statements, I'd likely go for something like this and do it all in one go:
SET #message = CONCAT('Status Report',
(SELECT CONCAT(' Events in assigned status with no primary unit: ',COUNT(*))
FROM event
WHERE status_name = 'ASSIGNED'
AND primary_unitid = NULL
OR status_name = 'ASSIGNED'
AND primary_unitid = ''
HAVING COUNT(*) > 0),
((SELECT CONCAT(' Un-linked unit resource table rows: ',COUNT (*))
FROM unit_resources ur
WHERE NOT EXISTS (SELECT 1 --I changed this from a NOT IN to an EXISTS, as NOT in have behave oddly with NULLs
FROM unit u
WHERE u.unit_seqnum = ur.seqnum)
HAVING COUNT(*) > 0))); --You get the idea now
I haven't done the whole lot here, however, the HAVING COUNT(*) > 0 means that no rows (including 0) will be returned when there are no relevant rows. This means that information won't be concatenated to the value of #message.

SQL Server : OR statement within CASE statement

I have a stored procedure that is querying some employee records based on what the user sends over.
On the UI, the user will enter multiple data points such as email addresses, User ID's, or Employee Names. This stored procedure checks what datatype they are providing and then searches that field in the database for the records.
Input to stored procedure:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<data>
<dataPoints>
<dataPoint>
<order>0</order>
<value>Jim Bob</value>
</dataPoint>
<dataPoint>
<order>1</order>
<value>Sally Jones</value>
</dataPoint>
</dataPoints>
</data>
</root>
Query:
#dataType VARCHAR (20), #data XML
AS
BEGIN
SET NOCOUNT ON;
BEGIN
-- Create a temp table
DECLARE #dataSet TABLE (data VARCHAR(100), [order] INT);
INSERT INTO #dataSet( data , [order] )
SELECT
ParamValues.x1.value('value[1]', 'VARCHAR(100)') ,
ParamValues.x1.value('order[1]', 'INT')
FROM
#data.nodes('/root/data/dataPoints/dataPoint') AS ParamValues(x1)
-- Search Employees
SELECT
ec.FirstName, ec.PreferredName, ec.LastName,
ec.NTID, ec.QID,
ec.DepartmentName, ec.SegmentName,
ec.CenterName, ec.RoleName, ec.MarketName,
ec.IncentivePlanName,
ec.CostCenterID,
ec.SupFirstName, ec.SupPreferredName, ec.SupLastName,
ec.SiloName,
ec.AreaName,
ec.PersonnelID,
d.[order]
FROM
Resources.emp.EmployeeComplete AS ec
INNER JOIN
#dataset AS d ON d.data = CASE
WHEN #dataType = 'NTID' THEN ec.ntid
WHEN #dataType = 'QID' THEN ec.QID
WHEN #dataType = 'Emp ID' THEN ec.EmpID
WHEN #dataType = 'Email Address' THEN ec.Email
WHEN #dataType = 'Personnel ID' OR #dataType = 'Sap ID' THEN ec.PersonnelID
--WHEN #dataType = 'Name' THEN (
-- (ec.FirstName + ' ' + ec.LastName)
-- OR (ec.PreferredName + ' ' + ec.LastName)
-- OR (ec.LastName + ', ' + ec.FirstName)
-- OR (ec.LastName + ', ' + ec.PreferredName
-- )
END
FOR XML PATH ('employees'), ELEMENTS, TYPE, ROOT ('root');
In short, I take the multiple data points being searched and throw them into an XML string to pass to the stored procedure. Once they arrive, I put them into a temp table so that I can join that with my main employee records.
The problem / question:
You will see I have some commented out code in my example and this is where my issue is. There are three name fields in my database. First Name, Preferred Name, Last Name.
I essentially need to test what the user provided and find employees based on the combination they entered them. All the user selects in the UI is that they are providing a name but not the format that its in.
For this reason, I need to check to see if I can find records in a couple of different formats.
Issue in this case is that I can't join my dataset using OR conditions in the CASE statement.
If #dataType = 'Name', I need to be able to join my temp table on a couple of the different combination possibilities.
The one thing we do make them aware of is that they can't mix and match. Meaning they cant do a FirstName LastName with a LastName FirstName search.
I had trouble explaining this so please let me know if I need to somehow clarify.
Push the equations in the CASE. If they are true let the THEN return 1. Check if the CASE returned 1. If and only if it did, you've found a match. In the conditions of WHEN you can use Boolean operators. So you can build your OR (or use IN as i did below) there.
...
CASE
WHEN #dataType = 'NTID' AND d.data = ec.ntid THEN 1
WHEN #dataType = 'QID' AND d.data = ec.QID THEN 1
...
WHEN (#dataType = 'Personnel ID' OR #dataType = 'Sap ID') AND d.data = ec.PersonnelID THEN 1
WHEN #dataType = 'Name' AND (d.data IN ('' + ec.FirstName + ' ' + ec.LastName,
'' + ec.PreferredName + ' ' + ec.LastName,
'' + ec.LastName + ', ' + ec.FirstName,
'' + ec.LastName + ', ' + ec.PreferredName) THEN 1
END = 1
...
What about just putting ORs in your join?
FROM #dataset AS d
INNER JOIN Resources.emp.EmployeeComplete AS ec
ON (#dataType = 'NTID' AND ec.ntid = d.data)
OR (#dataType = 'QID' AND ec.QID = d.data)
OR (#dataType = 'Emp ID' AND ec.EmpID = d.data)
OR (#dataType = 'Email Address' AND ec.Email = d.data)
OR ((#dataType = 'Personnel ID' OR #dataType = 'Sap ID') AND ec.PersonnelID = d.data)
OR (#dataType = 'Name' AND (ec.FirstName + ' ' + ec.LastName) = d.data)
OR (#dataType = 'Name' AND (ec.PreferredName + ' ' + ec.LastName) = d.data)
OR (#dataType = 'Name' AND (ec.LastName + ', ' + ec.FirstName) = d.data)
OR (#dataType = 'Name' AND (ec.LastName + ', ' + ec.PreferredName) = d.data)
I'm not sure if SQL is smart enough to use the proper indexes on those fields if you have them, probably especially not when combining columns. You would create indexed views for those combined names, or computed columns you could index on. It may be better to spread them out into separate queries in if/thens so SQL could optimize each query based on the field you are joining on and just execute the one query.

Invalid length parameter passed to the LEFT or SUBSTRING function in my query. It runs perfect id DTS 2008 but gives this error in SSIS 2014

DECLARE #ColumnTotal INT,
#HTProcOfficeColumnNames NVARCHAR(4000),
#TBLColumnNames NVARCHAR(4000),
#query NVARCHAR(4000),
#subqueryInsert NVARCHAR(4000),
#subqueryValues NVARCHAR(4000)
SELECT #ColumnTotal = Count(*)
FROM (SELECT htprocoffice
FROM table
WHERE COLUMN NOT LIKE '% - CO'
GROUP BY COLUMN) T
SELECT #HTProcOfficeColumnNames = COALESCE(#HTProcOfficeColumnNames
+ ',[' + htprocoffice + ']', '[' + htprocoffice + ']')
FROM (SELECT htprocoffice
FROM table
WHERE COLUMN NOT LIKE '% - CO'
GROUP BY COLUMN) T
ORDER BY COLUMN
SELECT #TBLColumnNames = COALESCE(#TBLColumnNames + ',' + NAME, NAME)
FROM table
WHERE id IN (SELECT id
FROM table
WHERE type = 'U'
AND NAME = 'TableName')
AND NAME LIKE 'HTOffice%'
ORDER BY NAME
Is there any error in the below code?
set #subqueryInsert = substring(#TBLColumnNames,1,#ColumnTotal*11-1) --The error occurs here but not sure though.
set #subqueryInsert = 'INSERT INTO Table
(RunDate,OrderBy,Period,IConOffice,IConOfficeType,'+ #subqueryInsert+')'
set #subqueryValues =
replace(replace(#HTProcOfficeColumnNames,'[',''''), ']','''')

SQL OpenQuery - Escaping Quotes

Been trying for some hours to convert this to a query I can use with OPENQUERY in SQL Server 2014 (to use with Progress OpenEdge 10.2B via ODBC). Can't seem to get the escaping of the quote right. Can anyone offer some assistance? Is there a tool to do it?
(There's a SQL table called #tAPBatches that is used in this, but I omitted it from this code)
DECLARE
#NoDays AS INT = 30
,#Prefix AS VARCHAR(5) = 'M_AP_'
SELECT
#Prefix + LTRIM(CAST(gh.[Batch-Number] AS VARCHAR(20))) AS BatchNo
,gh.[Batch-Number] AS BatchNo8
, aph.[Reference-number] AS InvoiceNo
,aph.[Voucher-Number] AS VoucherNo
,aph.[Amount] AS InvoiceTotal
,gh.[Journal-Number] AS JournalNo
,4 AS FacilityID
,CASE aph.[voucher-type]
WHEN 'DM' THEN 5
ELSE 1
END AS DocType
,apb.[Batch-Desc] AS BatchDesc
,apb.[Posting-Date] AS PostingDate
,apb.[Posting-Period]
,apb.[Posting-Fiscal-Year]
,apb.[Batch-Status]
,apb.[Expected-Count]
,apb.[Expected-Amount]
,apb.[Posted-To-GL-By]
,'Broadview' AS FacilityName
,apb.[Date-Closed] AS BatchDate
,gh.[Posted-by] AS PostUser
,gh.[Posted-Date] AS PostDT
,gh.[Created-Date] AS CreateDT
,gh.[Created-By] AS CreateUser
,aph.[Supplier-Key] AS VendorID
,sn.[Supplier-Name]
,aph.[Invoice-Date] AS InvoiceDate
,-1 AS Total
,-1 AS Discount
,gh.[Posted-by] AS Username
,CASE gt.[Credit-Debit]
WHEN 'CR' THEN LEFT(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 2) + '.' + SUBSTRING(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 3, 6) + '.'
+ RIGHT(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 3)
ELSE NULL
END AS GLCreditAcct
,CASE gt.[Credit-Debit]
WHEN 'DR' THEN LEFT(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 2) + '.' + SUBSTRING(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 3, 6) + '.'
+ RIGHT(CAST(gacr.[GL-Acct] AS VARCHAR(20)), 3)
ELSE NULL
END AS GLDebitAcct
,CASE gt.[Credit-Debit]
WHEN 'CR' THEN gacr.[Report-Label]
ELSE NULL
END AS GLCreditDesc
,CASE gt.[Credit-Debit]
WHEN 'DR' THEN gacr.[Report-Label]
ELSE NULL
END AS GLDebitDesc
,'D' AS [Status]
,aph.[PO-Number] AS PoNo
,aph.[Terms-Code] AS TermsCode
,aph.[Due-Date] AS DueDate
,'' AS Comments
,aph.[Discount-Date] AS DiscountDate
,aph.[Discount-Amount] AS DiscountAmount
,aph.[Discount-Taken] AS DiscountTaken
,aph.[Amount] AS APAmount
,gt.[Amount]
,'BA REGULAR ' AS CheckBookID --ToDO
,0 AS Transferred
,aph.[voucher-type] AS VoucherType
,gt.[Credit-Debit]
,gacr.[Account-type]
,aph.[Freight-Ref-Num]
FROM
[Progress].[GAMS1].pub.[GL-Entry-Header] gh
INNER JOIN [Progress].[GAMS1].pub.[gl-entry-trailer] gt ON gt.[System-ID] = gh.[System-ID] AND gt.[Origin] = gh.[Origin] AND gt.[Journal-Number] = gh.[Journal-Number]
INNER JOIN [Progress].[GAMS1].pub.[apinvhdr] aph ON (gh.[Journal-Number] = aph.[Journal-Number]
OR (gh.[Journal-Num-Reversal-Of] = aph.[Journal-Number] AND aph.[Journal-Number] <> ' ' AND gh.[Journal-Num-Reversal-Of] <> ' '))
AND gh.[system-id] = aph.[system-id-gl]
AND gh.origin = 'inv'
AND gh.[system-id] = 'arcade'
INNER JOIN [Progress].[GAMS1].pub.[APInvoiceBatch] apb ON gh.[Batch-number] = apb.[Batch-number]
AND apb.[system-id] = 'lehigh'
AND apb.[Posted-To-GL] = 1
INNER JOIN [Progress].[GAMS1].pub.[GL-accts] gacr ON gacr.[system-id] = gt.[system-id]
AND gacr.[Gl-Acct-Ptr] = gt.[GL-Acct-Ptr]
INNER JOIN [Progress].[GAMS1].pub.[suppname] sn ON sn.[Supplier-Key] = aph.[Supplier-Key]
AND sn.[system-id] = 'arcade'
WHERE
gh.[Posted-Date] > CAST(DATEADD(DAY, -#NoDays, GETDATE()) AS DATE)
AND case
when CAST(gh."Posting-Period" as int) < 10 then gh."Posting-Year" + '0' + ltrim(gh."Posting-Period")
else gh."Posting-Year" + Ltrim(gh."Posting-Period")
end > '201501'
AND gh.[Batch-number] NOT IN (SELECT
BatchNo COLLATE SQL_Latin1_General_CP1_CI_AS
FROM
#tAPBatches)
TIA
MArk
Here's an example of what's giving me a syntax error. This works, but "M_AP_" is a parameter passed to SP
DECLARE
#NoDays AS INT = 5
,#Prefix AS VARCHAR(5) = 'M_AP_';
DECLARE
#InterestDate AS varchar(20)
SELECT #InterestDate = CAST(CAST(DATEADD(DAY, -#NoDays, GETDATE()) AS DATE) AS VARCHAR(20))
SELECT * FROM OPENQUERY(PROGRESS,
'SELECT TOP 100 ''M_AP_'' + LTRIM(CAST(gh."Batch-Number" AS VARCHAR(20))) AS BatchNo
, gh."Batch-Number"
This works, but when I try to swap in the variable I get Incorrect Syntax near '+'
DECLARE
#NoDays AS INT = 5
,#Prefix AS VARCHAR(5) = 'M_AP_';
DECLARE
#InterestDate AS varchar(20)
SELECT #InterestDate = CAST(CAST(DATEADD(DAY, -#NoDays, GETDATE()) AS DATE) AS VARCHAR(20))
SELECT * FROM OPENQUERY(PROGRESS,
'SELECT TOP 100 '' ' + #Prefix + ' '' + LTRIM(CAST(gh."Batch-Number" AS VARCHAR(20))) AS BatchNo
, gh."Batch-Number"
FROM
"GAMS1".pub."GL-Entry-Header" gh
OPENQUERY will only support a string literal query that is less than 8K. You might be running into that limit if you've got even more code that you're not showing here. Make sure that your query is less than 8000 bytes, or create procedures or views to reduce the size of your query.
It only accepts a single string literal... so if you are trying to concatenate strings and parameters together, it will not work. There are some ways to work around this by using dynamic SQL or creating supporting tables or views for filters.

How Can we use ISNULL to all Column Names in SQL Server 2008?

I have a question
I tried to google it but looks like they don't like *
I'm using SQL Server 2008.
I have the following database table:
P_Id ProductName UnitPrice UnitsInStock UnitsOnOrder
------------------------------------------------------------------------
1 Jarlsberg 10.45 16 15
2 Mascarpone Null 23 NULL
3 Gorgonzola 15.67 9 20
If I need to replace the null with a string I know I do :
SELECT ISNULL(UnitsOnOrder,'No Data') FROM tbl
Questions
How can I use ISNULL() with multi column names ?
is it possible to use it with *
Like
SELECT ISNULL(* , 'NO data') FROM tbl
I think this will be tricky because of the datatype, you can't pass string to INT datatype so how can I fix this too
Update
Okay if i use ISNULL() with a datatype of int it will return 0
which will be a value to me , how can i pass empty string instead ?
You can use ISNULL multiple times in the same SQL statement for different columns, but you must write it separately for each column:
SELECT
ISNULL(ProductName, 'No Data') AS ProductName,
ISNULL(CAST(UnitPrice AS NVARCHAR), 'No Data') AS UnitPrice,
ISNULL(CAST(UnitsInStock AS NVARCHAR), 'No Data') AS UnitsInStock,
ISNULL(CAST(UnitsOnOrder AS NVARCHAR), 'No Data') AS UnitsOnOrder
FROM tbl
If you are building a dynamic SQL query, you could theoretically gather a list of columns in the table and generate a query with ISNULL on each one. For example:
DECLARE #SQL nvarchar(max)
SET #SQL = 'SELECT '
SELECT #SQL = #SQL + 'ISNULL(CAST([' + sc.name + '] AS NVARCHAR), ''No Data'') AS [' + sc.name + '],'
FROM sys.objects so
INNER JOIN sys.columns sc ON sc.object_id = so.object_id
WHERE so.name = 'tbl'
-- Remove the trailing comma
SELECT #SQL = LEFT(#SQL, LEN(#SQL) - 1) + ' FROM tbl'
EXEC sp_sqlexec #SQL
This code has problems when converting some column types like timestamps to an nvarchar, but it illustrates the technique.
Note that if you had another column that should be returned if a value is null, you could use the COALESCE expression like this:
SELECT COALESCE(ProductName, P_Id) AS Product...
Try this...
ISNULL (COALESCE (column1, column2), 'No Data')
You would need to include all column names though, you can't use *
COALESCE returns the first non-null value in its argument list so if they are all null it will return null