do i need to rewrite the case statement for every field? - sql

The case condition for two columns is same.in the below statement am using this twice but for different column, is there any other way for not repeating the condition twice ??
case [CPHIL_AWD_CD]
when ' ' then 'Not Applicable/ Not a Doctoral Student'
when 'X' then 'Not Applicable/ Not a Doctoral Student'
when 'N' then 'NO'
when 'Y' then 'YES'
end as CPHIL_AWD_CD
,case [FINL_ORAL_REQ_CD]
when ' ' then 'Not Applicable/ Not a Doctoral Student'
when 'X' then 'Not Applicable/ Not a Doctoral Student'
when 'N' then 'NO'
when 'Y' then 'YES'
end as FINL_ORAL_REQ_CD

Just create a table (temp?) with the mapping
CREATE TABLE [Constants]
(
[ID] nvarchar(1) PRIMARY KEY,
[Text] nvarchar(max)
)
INSERT INTO [Constants] VALUES (' ', 'Not Applicable/ Not a Doctoral Student')
INSERT INTO [Constants] VALUES ('X', 'Not Applicable/ Not a Doctoral Student')
INSERT INTO [Constants] VALUES ('N', 'No')
INSERT INTO [Constants] VALUES ('Y', 'Yes')
and perform an inner join
SELECT C1.Text AS CPHIL_AWD_CD, C2.Text AS FINL_ORAL_REQ_CD, ...
FROM YourTable T
INNER JOIN Constants C1 ON C1.ID = T.CPHIL_AWD_CD
INNER JOIN Constants C2 ON C2.ID = T.FINL_ORAL_REQ_CD

A variation on thepirat000's answer:
-- Sample data.
declare #Samples as Table (
Frisbee Int Identity Primary Key, Code1 Char(1), Code2 Char(2) );
insert into #Samples values ( 'Y', 'N' ), ( ' ', 'Y' ), ( 'N', 'X' );
select * from #Samples;
-- Handle the lookup.
with Lookup as (
select * from ( values
( ' ', 'Not Applicable/ Not a Doctoral Student' ),
( 'X', 'Not Applicable/ Not a Doctoral Student' ),
( 'N', 'No' ),
( 'Y', 'Yes' ) ) as TableName( Code, Description ) )
select S.Code1, L1.Description, S.Code2, L2.Description
from #Samples as S inner join
Lookup as L1 on L1.Code = S.Code1 inner join
Lookup as L2 on L2.Code = S.Code2;
The lookup table is created within a CTE and referenced as needed for multiple columns.
Update: The table variable is now blessed with a primary key for some inexplicable reason. If someone can actually explain how it will benefit performance, I'd love to hear it. It isn't obvious from the execution plan.

As per the suggestion from Dijkgraaf, here is the solution:
Create a function with the logic in it and call that in the select statement:
CREATE FUNCTION dbo.GetCaseValue (#val varchar(50))
RETURNS varchar(50)
WITH EXECUTE AS CALLER
AS
BEGIN
return (select case #val
when ' ' then 'Not Applicable/ Not a Doctoral Student'
when 'X' then 'Not Applicable/ Not a Doctoral Student'
when 'N' then 'NO'
when 'Y' then 'YES'
end)
END
And call it like:
select dbo.GetCaseValue([CPHIL_AWD_CD]) as 'CPHIL_AWD_CD',
dbo.GetCaseValue([FINL_ORAL_REQ_CD]) as 'FINL_ORAL_REQ_CD'

Not really. What you are doing is, to the best of my knowledge, correct.
You COULD make a user defined function as below, but the benefits are .. subjective.
CREATE FUNCTION dbo.ufnMungeIt (
#In NVARCHAR(1)
)
RETURNS NVARCHAR(255)
BEGIN
RETURN CASE #In
when ' ' then 'Not Applicable/ Not a Doctoral Student'
when 'X' then 'Not Applicable/ Not a Doctoral Student'
when 'N' then 'NO'
when 'Y' then 'YES'
END
END
--
SELECT dbo.ufnMungeIt([CPHIL_AWD_CD]) AS CPHIL_AWD_CD,
dbo.ufnMungeIt([FINL_ORAL_REQ_CD]) AS FINL_ORAL_REQ_CD

Related

Is a Case statement what I need?

I am new to SQL and trying to merge two columns into a new table based upon a simple logic. I have been attempting a variety of CASE/WHEN statements but am hitting a wall.
Table: program / Columns C1, C2
The logic must be:
Use a case expression:
select c1, c2,
case when c1 = 'Yes' and c2 = 'Yes' then 'Both'
when c1 = 'Yes' then 'Regional'
when c2 = 'Yes' then 'Local'
else 'No'
end
from program
(The value for the first fulfilled condition will be returned.)
Is this what you are looking for?:
-- create test data in table variable #T
declare #T table
(
C1 nvarchar(3) null,
C2 nvarchar(3) null
)
insert into #T values (null, null)
insert into #T values (null, 'YES')
insert into #T values ('YES', null)
insert into #T values ('YES', 'YES')
insert into #T values ('NO', 'NO')
insert into #T values ('NO', 'YES')
insert into #T values ('YES', 'NO')
insert into #T values ('YES', 'YES')
-- get the wanted value in RESULT columns based on C1 and C2
select
C1, C2,
case
when ISNULL(C1, 'NO') = 'NO' and ISNULL(C2, 'NO') = 'NO' then 'NO'
when ISNULL(C1, 'NO') = 'NO' and C2 = 'YES' then 'LOCAL'
when C1 = 'YES' and ISNULL(C2, 'NO') = 'NO' then 'REGIONAL'
when C1 = 'YES' and C2 = 'YES' then 'BOTH'
end as RESULT
from #T
This will work in SQL Server.

How to INSERT into 1 table and UPDATE another table in one query

I have a question on how to write a single query to insert and update. Below is the scenario. I am trying to use 1 query for the part that is enclosed in (-----)
CREATE TABLE #TEMP
(
Ref VARCHAR(10),
Num INT,
[Status] VARCHAR(3)
)
INSERT INTO #TEMP
VALUES ('A123', 1, 'A3'), ('A123', 2, 'A3'), ('A123', 3, 'A3'),
('B123', 1, 'A1'), ('B123', 2, 'A3'),
('C123', 1, 'A1'), ('C123', 2, 'A2'), ('C123', 3, 'A3');
SELECT
Ref,
CASE WHEN A.TotalCount = A.DenialCount THEN 1 ELSE 0 END IsDenial
--CASE WHEN A.TotalCount <> A.DenialCount Then 1 else 0 end IsApproval
INTO
#TEMP1
FROM
(SELECT
Ref, COUNT(Num) TotalCount,
SUM(CASE WHEN [Status] = 'A1' THEN 1 ELSE 0 END) ApprovedCount,
SUM(CASE WHEN [Status] = 'A2' THEN 1 ELSE 0 END) PartialApprovalCount,
SUM(CASE WHEN [Status] = 'A3' THEN 1 ELSE 0 END) DenialCount
FROM
#temp
GROUP BY
Ref) A
UPDATE A
SET A.[Status] = CASE WHEN IsDenial = 1 THEN 'A3' ELSE 'A1' END
FROM #TEMP A
JOIN #TEMP1 B ON A.Ref = B.Ref
SELECT * FROM #TEMP
SELECT * FROM #TEMP1
DROP TABLE #TEMP
DROP TABLE #TEMP1
Any help would be appreciated.
"INSERT into 1 table and UPDATE another table in one query"
Nope. Some DBMSes support the idea of 'upsert' but that's insert/update in a single table.
Your looking for the MERGE statment. However I see several issues with the SQL in your post. In short it is generally more efficient to use set theory instead of thinking of optimisations per statement.
Rather than update, why not join in the data thats inserted into temp into the second query and produce the result you require?
hint ' SELECT 'ABC' as a, '123' as b, 456 as c UNION '

Using SQL CASE Statement how to find multiple items

I need to get a value for “THEN” from “Mortgage_Type” column if bellow conditions are true. Mortgage_Type and Category are same table and Equipment from another table. Tables are joining using Item_No. I need to find the Mortgage_Type of each item. I have 20+ Mortgage_Types if Category is main and Equipment is null then should display relevant Mortgage_Type
when SUM (Mortgage_Type)is not null and SUM (Equipment)is null and sum(Category) =’M’ THEN “value from Mortgage_Type column”
Maybe, this should help:
SELECT DISTINCT
Contract,
CASE
WHEN CATOGORY NOT IN ('M', 'O') AND TYPE NOT IN ('V', 'E')
THEN
CASE
WHEN M_TYPE = 'V' THEN 'VEHICLE'
WHEN M_TYPE = 'O' THEN 'OTHERS'
WHEN M_TYPE = 'M' THEN 'MORTGAGE'
WHEN M_TYPE = 'H' THEN 'HOUSE'
WHEN M_TYPE LIKE '%,%' THEN 'MULTIPLE'
END
END
AS TYPE
FROM Table1 LEFT JOIN Table2 ON Contract = ID
You could use a cte and a window function. Something like this:
DECLARE #t TABLE(
[Contract] int
,[M_TYPE] nvarchar(100)
)
INSERT INTO #t VALUES
(1, 'V')
,(1, 'O')
,(1, 'M')
,(2, 'V')
,(3, 'V')
,(4, 'H')
,(4, 'V');
WITH cte AS(
SELECT t.Contract,
t.M_TYPE,
COUNT(M_TYPE) OVER (PARTITION BY t.Contract) Multi
FROM #t t
)
SELECT DISTINCT [Contract], CASE
WHEN Multi > 1 THEN 'Multiple'
WHEN M_TYPE = 'V' THEN 'VEHICLE'
WHEN M_TYPE = 'O' THEN 'OTHERS'
WHEN M_TYPE = 'M' THEN 'MORTGAGE'
WHEN M_TYPE = 'H' THEN 'HOUSE'
ELSE 'UNKNOWN'
END AS MortgageType
FROM cte

How to ORDER BY one query only in a UNION ALL without subquery

I'm creating a list from unrelated data using UNION ALL in order to be saved to Excel in SQL Server 2008. Only one of the SELECT statements will have an ORDER BY and that is where my issue arises with the following error message
'The multi-part identifier "p.Category" could not be bound.'
This is a simplified working code example that I prefer to the second one below but breaks when uncommenting the first SELECT query:
CREATE TABLE #People(Category varchar(50), [Name] varchar(50));
INSERT INTO #People VALUES(1, 'Steve');
INSERT INTO #People VALUES(99, 'Anna');
INSERT INTO #People VALUES(2, 'Sarah');
-- Unrelated data SELECT query
--SELECT 'Best Employee' AS Matrix
-- , 'Alan' AS [Name]
--UNION ALL
SELECT CASE
WHEN p.Category = 1
THEN 'Very Active'
WHEN p.Category = 2
THEN 'Active '
ELSE 'Departed'
END AS Matrix
, p.name AS [Name]
FROM #People p
ORDER BY p.Category;
DROP TABLE #People;
After some research I found that I could rewrite the query in the following way, which would give me the desired result in this small example but not something that I would consider ideal in my real case. Is there a way to give me the correct result without resorting to sub queries like in the working example below?
CREATE TABLE #People(Category varchar(50), [Name] varchar(50));
INSERT INTO #People VALUES(1, 'Steve');
INSERT INTO #People VALUES(99, 'Anna');
INSERT INTO #People VALUES(2, 'Sarah');
SELECT *
FROM
(
-- Unrelated data SELECT query
SELECT 'Best Employee' AS Matrix
, 'Alan' AS [Name]
, '' AS Category
UNION ALL
SELECT CASE
WHEN p.Category = 1
THEN 'Very Active'
WHEN p.Category = 2
THEN 'Active '
ELSE 'Departed'
END Matrix
, p.name AS [Name]
, p.Category Category
FROM #People p
) x
ORDER BY x.Category;
DROP TABLE #People;
The ORDER BY doesn't apply to just one SELECT, it applies to the whole result set, to the whole result after all rows are UNIONed. So, you need to include columns that will be used for sorting in each SELECT of the UNION ALL.
For example, the following is wrong syntax, because ORDER BY has to be after the last SELECT of the UNION.
SELECT CASE
WHEN p.Category = 1
THEN 'Very Active'
WHEN p.Category = 2
THEN 'Active '
ELSE 'Departed'
END AS Matrix
, p.name AS [Name]
FROM #People p
ORDER BY p.Category
UNION ALL
SELECT 'Best Employee' AS Matrix
, 'Alan' AS [Name]
Your second example from the question can be written in a simpler form, without sub-query:
SELECT CASE
WHEN p.Category = 1
THEN 'Very Active'
WHEN p.Category = 2
THEN 'Active '
ELSE 'Departed'
END AS Matrix
, p.name AS [Name]
, p.Category
FROM #People p
UNION ALL
SELECT 'Best Employee' AS Matrix
, 'Alan' AS [Name]
, NULL AS Category --- or '' AS Category
ORDER BY Category;
In any case, the column Category has to be added in each SELECT statement of the UNION. I don't see how you can avoid it.
If your issue is that your ordering is causing the 2 tables from being mixed up, you could add a column so that the 1st select result set would be displayed first always.
CREATE TABLE #People(Category varchar(50), [Name] varchar(50));
INSERT INTO #People VALUES(1, 'Steve');
INSERT INTO #People VALUES(99, 'Anna');
INSERT INTO #People VALUES(2, 'Sarah');
SELECT Matrix, Name, Category
FROM
(
-- Unrelated data SELECT query
SELECT 'Best Employee' AS Matrix
, 'Alan' AS [Name]
, '' AS Category
, 1 as Ord
UNION ALL
SELECT CASE
WHEN p.Category = 1
THEN 'Very Active'
WHEN p.Category = 2
THEN 'Active '
ELSE 'Departed'
END Matrix
, p.name AS [Name]
, p.Category Category,
2 as Ord
FROM #People p
) x
ORDER BY x.Ord --,Additional Order by columns

SQL Select the first Column to match criteria of Many columns in a single row

Good Day,
So I'm stuck with a SQL query in which the table I'm querying has multiple sequential columns, such as
Property1,
Property2,
Property3,
Property4,
Property5
..etc
Now there are about 64 columns descending in the same naming convention.
They are varchar of type and marked by a single "Y" or "N" stating boolean function.(Not my design)
Now where I'm stuck is that in my query I need to return the First Property column that's marked as "Y" in a single record..
I've searched around but could not have come upon the same question asked elsewhere.. Maybe I'm just missing it?
It would really be appreciated should anyone have a hint for me to follow or so on?
Thanks in advance!
The basic idea is to concatenate all fields in one string and then find the index of the first occurrence of Y and form a field label as PROPERTY+FIRST OCCURRENCE INDEX.
If Y is not found then PROPERTY0 appears in this query you can handle this with CASE statement for example.
SQLFiddle demo
select id,
'PROPERTY'+
CONVERT(VARCHAR(10),CHARINDEX('Y',property1+property2+property3))
from T
You could consider unpivot
declare #t table(id int identity(1,1), Property1 char(1),
Property2 char(1),
Property3 char(1),
Property4 char(1),
Property5 char(1))
insert #t values('N', 'Y', 'Y', 'N', 'Y')
insert #t values('N', 'N', 'Y', 'N', 'Y')
insert #t values('N', 'N', 'N', 'N', 'Y')
;with a as
(
select *, row_number() over (partition by id order by id) position from #t
unpivot
(Property FOR colname IN
([Property1], [Property2], [Property3], [Property4],
[Property5]/*include more properties here*/) ) AS unpvt
)
select t.id, coalesce(colname, 'Not found') colname
from #t t
outer apply
(select top 1 id, colname, position
from a where Property = 'Y'
and t.id = id
order by id
) x
that design is horrible. But this should work:
SELECT CASE WHEN Property1 = 'Y' THEN 'Property1'
WHEN Property2 = 'Y' THEN 'Property2'
[...]
ELSE 'None'
END
Try this:
select
CASE WHEN QryGroup1 = 'Y' then 'QryGroup1'
WHEN QryGroup2 = 'Y' then 'QryGroup2'
WHEN QryGroup3 = 'Y' then 'QryGroup3'
WHEN QryGroup10 = 'Y' then 'QryGroup10'
else ''
end as [SelectedBP]
from OCRD
This could work as well:
SELECT CHARINDEX ( 'Y' , CONCAT(Property1,Property2,...,Property64) )
It returns a numeric index of the column and it has the advantage that you can define a function based index to speed up the query.