TSQL if statement within - tsql

I have 160 columns like below
name,preweight,postweight,prebp,postbp,presugar,postsugar...
I am trying to include new column at the end for the list of factors (like weight is different between pre and post, sugar is different pre and post.).
Written sql like below
select name,preweight,postweight,prebp,postbp,presugar,postsugar
case
when (preweight!=postweight)
then 'weight changed'
when (presugar!=postsugar)
then 'sugar changed'
end
from clientinfo
now always shows one changed. but how I can list all the factors which are changed?

One option uses concat_ws() and a series of case expressions:
select
name,
preweight,
postweight,
prebp,
postbp,
presugar,
postsugar
concat_ws(
', '
case when preweight <> postweight then 'weight changed' end,
case when prebp <> postbp then 'bp changed' end,
case when presugar <> postsugar then 'sugar changed' end
) what_changed
from clientinfo

Related

Crystal formula case statement with like

I'm trying to convert sql case statement to crystal formula.
The select in sql had this in it:
...
,pf.Status_category AS Category
,CASE WHEN p.degree LIKE '%P%' AND
pf.department_name LIKE 'Occ%' THEN isnull(pf.department2, '') ELSE isnull(pf.department_name, '') END AS Department,
CASE WHEN p.degree LIKE '%P%' AND pf.department_name LIKE 'Occ%' THEN isnull(pf.Section2, '') ELSE isnull(pf.Section_name, '') END AS Section,
CASE WHEN p.degree LIKE '%P%' AND pf.department_name LIKE 'Occ%' THEN isnull(pf.department3, '') ELSE isnull(pf.department2, '') END AS [Department 2],
CASE WHEN p.degree LIKE '%P%' AND pf.department_name LIKE 'Occ%' THEN isnull(pf.Section3, '') ELSE isnull(pf.Section2, '') END AS [Section 2],
pdd.DepartmentName AS DP
,pdv.PrivilegeDetailText AS Privilages
...
FROM dbo.Person_PrivDtl_V AS pdv INNER JOIN
dbo.Person_Privs_Facs_V ON pdv.M_ID = dbo.Person_Privs_Facs_V.Person_Priv_M_ID INNER JOIN
dbo.PrivDefDepartments_PDF AS pdd ON pdd.PDDept_ID = pdv.PDDept_ID INNER JOIN
dbo.Person AS p ON pdv.Person_ID = p.Person_ID INNER JOIN
dbo.Person_Facilities AS pf ON pf.FacCode = dbo.Person_Privs_Facs_V.FacCode AND pdv.Person_ID = pf.Person_ID
When I convert this to crystal, I can't put this in the columns of the report design. So my idea is to use a formula for each column selected. I have this so far for the first formula, but it won't let me save it:
Formula name= Department:
select {Person_Facilities.Department_name}
case is like "Occ%" : {Person_Facilities.Department2}
The error seems to be the like. I looked up crystal like and it seems ok except for they use "is" for the accepted answer, but when I add "is" the error seems to be the "is" when I try to save it.
What is wrong with this formula so I can use like and the case?
Is there a better way to do this? I suppose I can use a view, but my boss doesn't want views cluttering the DB. Is using a formula the way to do this in crystal? The sql also handled null, which I'm not doing, but I'm not sure how to incorporate that at this point. I'm pretty new to crystal and my team doesn't like questions. We have Crystal Reports 2008 and SQL server 2008 R2.
Not sure if this is what you are looking for but try this;
select {Person_Facilities.Department_name}
case "Occ%" : {Person_Facilities.Department2}
default : 'Unknown';
The default is optional.
To use the LIKE operator, it is as follows;
If {Command_Main.Name} LIKE '*Manager*' then Do Something
To handle NULLS in CR, there is an option to do so in the formula editor. See below. Change it from Exception for Nulls to Default Values for Nulls.

Convert value to unique value (ex John to John_1)

The user writes his name and i want to store it into the database. If the name is already in the database i want to insert a postfix. ie Convert 'John' to the first one available between ('John_1', 'John_2' ... etc).
This is my way of doing this so far, but i'm sure there's a better way.
select n from
(
select 'John' n ,0 v
union
select 'John'||'_'||generate_series(1,100),generate_series(1,100)
) possible_names
where n not in
(select my_name from all_names u)
order by v
limit 1
Any suggestions?
If you need to worry about concurrency, the simplest way to guarantee uniqueness is by issuing insert statements until one succeeds. (This assumes you've a unique constraint, of course.)
Pseudocode:
while true
if db.execute(insert_sql, [..., name + postfix, ...])
break
end
counter += 1
postfix = '_' + counter
end
You can make the procedure run in a shorter amount of time by starting at the maximum existing postfix (see the other answers with approaches to do that).
An awkward alternative would be to find the maximum existing postfix using a select statement, and then to try to acquire an advisory lock on something unique to the applicable name and postfix, e.g. 'username:' + name + postfix. It's much less robust though, because it opens up the possibility of two transactions finding the same max_postfix, and then one transaction trying to acquire the lock immediately after other is done committing its insert and releasing that lock -- thus resulting in a duplicate.
SELECT CASE WHEN num IS NULL THEN 'John' ELSE 'John' || '_' || num END AS new_name
FROM (
SELECT max(substr(my_name, position('_' in my_name) + 1)::int) + 1 AS num
FROM all_names
WHERE my_name ilike 'John' || '_%'
) new_number
With all three instances of 'John' being where you pass in the name entered. (This is assuming that the user can't make an underscore part of their name and a number will always follow the underscore.)
Edit: This is also assuming that 'John' and 'john' should be treated the same. If they shouldn't, then replace the ilike with like instead.
CREATE FUNCTION get_username_proposal(text) RETURNS text AS $$
SELECT
CASE WHEN (SELECT COUNT(*) FROM all_names WHERE my_name = $1)=0 THEN
$1
ELSE
$1 || '_' || COALESCE(MAX(LTRIM(SUBSTRING(my_name FROM '_[0-9]+$'), '_')::int), 0)+1
END
FROM
all_names
WHERE
my_name ~ ($1 || '_[0-9]+$');
$$ LANGUAGE SQL STABLE;

Case statement with 'not like' possible?

I’m looking to case all bacheloreatte degrees that are not BA’s or BS’s seperately (BSAST for example). I tried a nested case statement, but as I’m relatively new to t-sql I'm not sure if it was my syntax or that it’s not possible. Note that this is in a select statement.
SELECT
t2.ID,
t2.ACAD_PROGRAM,
'092013' AS T01,
'274842' AS T02,
REPLACE(p.SSN,'-','') AS T03,
'5' AS T04,
ap.ACPG_CIP AS T05,
CASE(t2.ACAD_PROGRAM)
WHEN 'BA%' THEN '1'
WHEN 'BS' THEN '2'
ELSE (CASE
WHEN t4.STP_DEGREE LIKE 'BA%'
THEN '1' END)
END AS T06
CASE has two formats, to be able to use with LIKE operator, your first CASE should be a Searched Case:
SELECT t2.ID, t2.ACAD_PROGRAM, '092013' AS T01, '274842' AS T02,
REPLACE(p.SSN,'-','') AS T03, '5' AS T04, ap.ACPG_CIP AS T05,
CASE WHEN t2.ACAD_PROGRAM LIKE 'BA%' THEN '1'
WHEN t2.ACAD_PROGRAM = 'BS' THEN '2'
ELSE
CASE WHEN t4.STP_DEGREE LIKE 'BA%' THEN '1' END
END AS T06
FROM yourTable

SELECT..CASE - Refactor T-SQL

Can I refactor the below SQL CASE statements into single for each case ?
SELECT
CASE RDV.DOMAIN_CODE WHEN 'L' THEN CN.FAMILY_NAME ELSE NULL END AS [LEGAL_FAMILY_NAME],
CASE RDV.DOMAIN_CODE WHEN 'L' THEN CN.GIVEN_NAME ELSE NULL END AS [LEGAL_GIVEN_NAME],
CASE RDV.DOMAIN_CODE WHEN 'L' THEN CN.MIDDLE_NAMES ELSE NULL END AS [LEGAL_MIDDLE_NAMES],
CASE RDV.DOMAIN_CODE WHEN 'L' THEN CN.NAME_TITLE ELSE NULL END AS [LEGAL_NAME_TITLE],
CASE RDV.DOMAIN_CODE WHEN 'P' THEN CN.FAMILY_NAME ELSE NULL END AS [PREFERRED_FAMILY_NAME],
CASE RDV.DOMAIN_CODE WHEN 'P' THEN CN.GIVEN_NAME ELSE NULL END AS [PREFERRED_GIVEN_NAME],
CASE RDV.DOMAIN_CODE WHEN 'P' THEN CN.MIDDLE_NAMES ELSE NULL END AS [PREFERRED_MIDDLE_NAMES],
CASE RDV.DOMAIN_CODE WHEN 'P' THEN CN.NAME_TITLE ELSE NULL END AS [PREFERRED_NAME_TITLE]
FROM dbo.CLIENT_NAME CN
JOIN dbo.REFERENCE_DOMAIN_VALUE RDV
ON CN.NAME_TYPE_CODE = RDV.DOMAIN_CODE AND RDV.REFERENCE_DOMAIN_ID = '7966'
No, you will require 8 separate statements as case and other such variants can only be used in a select to modify the results of a single column, not a series of columns.
If RDV.DOMAIN_COD can only by 'P' or 'L' use NULLIf. It's cleaner.
NULLIF ( expression , expression )
NULLIF is equivalent to a searched CASE expression in which the two expressions are equal and the resulting expression is NULL.
SELECT
NullIf('P', RDV.DOMAIN_CODE) AS [LEGAL_FAMILY_NAME],
...
NullIf('L', RDV.DOMAIN_CODE) AS [PREFERRED_FAMILY_NAME],
...
Since a CASE expression returns a single value, you cannot take eight CASE expressions returning 8 values and make a single CASE expression that returns all eight.
A less efficient alternative with no cases:
SELECT LEGAL_FAMILY_NAME, LEGAL_GIVEN_NAME, LEGAL_MIDDLE_NAMES, LEGAL_NAME_TITLE,
PREFERRED_FAMILY_NAME, PREFERRED_GIVEN_NAME, PREFERRED_MIDDLE_NAMES, PREFERRED_NAME_TITLE
FROM dbo.REFERENCE_DOMAIN_VALUE RDV
LEFT OUTER JOIN
( SELECT
NAME_TYPE_CODE,
FAMILY_NAME AS [LEGAL_FAMILY_NAME],
GIVEN_NAME AS [LEGAL_GIVEN_NAME],
MIDDLE_NAMES AS [LEGAL_MIDDLE_NAMES],
NAME_TITLE AS [LEGAL_NAME_TITLE]
FROM dbo.CLIENT_NAME
WHERE NAME_TYPE_CODE = 'L') LN ON RDV.DOMAIN_CODE = LN.NAME_TYPE_CODE
LEFT OUTER JOIN
( SELECT
NAME_TYPE_CODE,
FAMILY_NAME AS [PREFERRED_FAMILY_NAME],
GIVEN_NAME AS [PREFERRED_GIVEN_NAME],
MIDDLE_NAMES AS [PREFERRED_MIDDLE_NAMES],
NAME_TITLE AS [PREFERRED_NAME_TITLE]
FROM dbo.CLIENT_NAME
WHERE NAME_TYPE_CODE = 'P') PN ON RDV.DOMAIN_CODE = PN.NAME_TYPE_CODE
WHERE RDV.REFERENCE_DOMAIN_ID = '7966'
You could also use a temp table or table variable with all 8 columns and then do two inserts. You could also use a UNION ALL. My guess is that the 8 case statements are the most efficient way. This is especially true if you have some key where you will want some type of ClientID, Legal Names, Preferred Names so you will wrap a MAX around the cases or something and group by a ClientID......
You could generate the SQL script using syscols/INFORMATION_SCHEMA.columns with two case whens for each column 'CASE WHEN DOMAIN_CODE = ''P'' THEN ' + COLUMN_NAME + ' ELSE NULL END AS PREFERRED_' + COLUMN_NAME and then another for L. You could make a LOOP so that the same code executes once for P and once for L and get it down to one loop. Then you could EXEC the string directly, or PRINT it and put it into your SQL script. Anyway for just 8 columns I would cut/paste the case statements...
But anyway in general T-SQL is limited on being able to do for eaches over columns. Either you generate the script using a code generator (done in t-sql or another programming language) or you rethink your problem in another way. But many times you get better performance from duplicate cut/paste code. And many times it isn't worth the hassle of writing an external code generator (ie just for 8 case statements).

DESCENDING/ASCENDING Parameter to a stored procedure

I have the following SP
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = #webRegionID)
ORDER BY
CASE UPPER(#sortBy)
when 'CASE_NO' then case_no
when 'AREA' then area
when 'FURNISHED' then furnished
when 'TYPE' then [type]
when 'SQUAREFEETS' then squarefeets
when 'BEDROOMS' then bedrooms
when 'LIVINGROOMS' then livingrooms
when 'BATHROOMS' then bathrooms
when 'LEASE_FROM' then lease_from
when 'RENT' then rent
else case_no
END
END
GO
Now everything in that SP works but I want to be able to choose whether I want to sort ASCENDING or DESCENDING.
I really can't fint no solution for that using SQL and can't find anything in google.
As you can see I have the parameter sortDirection and I have tried using it in multiple ways but always with errors... Tried Case Statements, IF statements and so on but it is complicated by the fact that I want to insert a keyword.
Help will be very much appriciated, I have tried must of the things that comes into mind but haven't been able to get it right.
You could use two order by fields:
CASE #sortDir WHEN 'ASC' THEN
CASE UPPER(#sortBy)
...
END
END ASC,
CASE #sortDir WHEN 'DESC' THEN
CASE UPPER(#sortBy)
...
END
END DESC
A CASE will evaluate as NULL if none of the WHEN clauses match, so that causes one of the two fields to evaluate to NULL for every row (not affecting the sort order) and the other has the appropriate direction.
One drawback, though, is that you'd need to duplicate your #sortBy CASE statement. You could achieve the same thing using dynamic SQL with sp_executesql and writing a 'ASC' or 'DESC' literal depending on the parameter.
That code is going to get very unmanageable very quickly as you'll need to double nest your CASE WHEN's... one set for the Column to order by, and nested set for whethers it's ASC or DESC
Might be better to consider using Dynamic SQL here...
DECLARE #sql nvarchar(max)
SET #sql = '
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = ' + #webRegionID + ') ORDER BY '
SET #sql = #sql + ' ' + #sortBy + ' ' + #sortDirection
EXEC (#sql)
You could do it with some dynamic SQL and calling it with an EXEC. Beware SQL injection though if the user has any control over the parameters.
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
DECLARE #dynamicSQL NVARCHAR(MAX)
SET #dynamicSQL =
'
SELECT
tbl_houses.*
FROM
tbl_houses
WHERE
postal
IN
(
SELECT
zipcode
FROM
crm_zipcodes
WHERE
web_region_id = ' + CONVERT(nvarchar(10), #webRegionID) + '
)
ORDER BY
' + #sortBy + ' ' + #sortDirection
EXEC(#dynamicSQL)
END
GO