Using SQL CASE Statement how to find multiple items - sql

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

Related

How to fetch records using vertical columns

I need to fetch records between the date range given in two columns.
My Table structure is like:
CREATE TABLE shared
(
id integer NOT NULL,
product varchar(50) NOT NULL,
parent_id integer NOT NULL,
key_code varchar(100) NOT NULL,
key_value varchar(8000)
);
INSERT INTO shared
(`id`, `product`, `parent_id`, 'key_code', 'key_value')
VALUES
(1, 'a',1, 'start_date','1/7/2011'),
(2, 'a', 1,'end_date','15/7/2011'),
(3, 'a',1, 'type','Promotion'),
(4, 'a',1,'plan', 'new'),
(5, 'a',5, 'start_date','11/8/2012'),
(6, 'a', 5,'end_date','15/8/2012'),
(7, 'a',5, 'type','Promotion'),
(8, 'a',5,'plan', 'new'),
(9, 'b',9, 'start_date','15/09/2015'),
(10, 'b', 9,'end_date','15/09/2016'),
(11, 'b',9, 'type','Promotion'),
(12, 'b',9,'plan', 'new'),
;
Now i want to fetch all the records between start date>='1/7/2011' to start_date<='15/8/2012' where product='a'.
The Query I tried is:
SELECT
*
FROM
(SELECT parent_id,
product,
MIN(CASE WHEN key_code = 'key_code' THEN key_value ELSE 'n/a' END) AS key_code,
MIN(CASE WHEN key_code = 'start_date' THEN key_value ELSE 'n/a' END) AS start_date,
MIN(CASE WHEN key_code = 'end_date' THEN key_value ELSE 'n/a' END) AS end_date,
MIN(CASE WHEN key_code = 'type' THEN key_value ELSE 'n/a' END) AS type,
MIN(CASE WHEN key_code = 'plan' THEN key_value ELSE 'n/a' END) AS plan,
FROM shared
GROUP BY parent_id,
product
ORDER BY parent_id) comp
WHERE
start_date>= '01/12/2011'
AND start_date <= '02/17/2011' and product='a';
I am getting records now, changed the date format.
But is there any way to optimize this query.? Like this will take time to execute when records are in numbers.
Your dates have not the MySQL format, so they have to be converted,to be compared
With the MIN and MAX and your 'n/a, it is better to use NULL in the inner Select and in the outer assign the Value n/a if the value is NULL, ot or else you get n/qa even if there is data.
SELECT
*
FROM
(SELECT
parent_id,
product,
MIN(CASE WHEN key_code = 'start_date' THEN key_value ELSE 'n/a' END) AS start_date,
MIN(CASE WHEN key_code = 'end_date' THEN key_value ELSE 'n/a' END) AS end_date,
MAX(CASE WHEN key_code = 'type' THEN key_value ELSE 'n/a' END) AS type,
MAX(CASE WHEN key_code = 'plan' THEN key_value ELSE 'n/a' END) AS plan
FROM
shared
GROUP BY parent_id , product
ORDER BY parent_id) comp
WHERE
TO_DATE(start_date, 'DD/MM/YYYY') >= '2011-01-12'
AND TO_DATE(start_date, 'DD/MM/YYYY') <= '2011-07-17'
AND product = 'a'
;
Thsi would give youz
parent_id product start_date end_date type plan
1 a 1/7/2011 15/7/2011 Promotion new
So STR:TO:DATE doesn't exist in AWS but it EXISTS a TO_Date
Instead of IF you maust do A CASe when like in your query

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 '

Return SQL results back as a single row for case scenarios

So I have the following SQL query:
SELECT CASE
WHEN STATUS = 0 THEN 'Pending'
WHEN STATUS = 1 THEN 'Pending'
WHEN STATUS = 2 THEN 'Confirmed'
WHEN STATUS = 3 THEN 'Pending'
WHEN STATUS = 4 THEN 'Pending'
WHEN STATUS = 5 THEN 'Pending'
WHEN STATUS = 6 THEN 'Paid'
WHEN STATUS = 7 THEN 'Closed'
WHEN STATUS = 8 THEN 'Rejected' END AS Statuses
FROM ORDERS
WHERE opportunityid = 4054
GROUP BY Statuses
Which returns the following results:
Pending
Confirmed
However, I am trying to achieve the following:
Pending,Confirmed
Can this be done without the use of a #declare function too.
I think you want something like this:
SELECT STUFF(MAX(CASE WHEN STATUS IN (0, 3, 4, 5) THEN ',Pending' ELSE '' END) +
MAX(CASE WHEN STATUS IN (2) THEN ',Confirmed' ELSE '' END) +
MAX(CASE WHEN STATUS IN (6) THEN ',Paid' ELSE '' END) +
MAX(CASE WHEN STATUS IN (7) THEN ',Closed' ELSE '' END) +
MAX(CASE WHEN STATUS IN (8) THEN ',Rejected' ELSE '' END),
1, 1, ''
) as statuses
FROM ORDERS
WHERE opportunityid = 4054;
This will for status which are not predefined but exists in a table:
DECLARE #t table(STATUSES INT,opportunityid INT)
INSERT #t values(1,4054),(2,4054),(3,4054)
INSERT #t values(1,4055),(6,4055),(7,4055),(12,4055)
DECLARE #t2 table(sta int, txt varchar(30))
INSERT #t2
values
(0, 'Pending'),
(1, 'Pending'),
(2, 'Confirmed'),
(3, 'Pending'),
(4, 'Pending'),
(5, 'Pending'),
(6, 'Paid'),
(7, 'Closed'),
(8, 'Rejected')
;WITH CTE as
(
SELECT distinct opportunityid FROM #t
)
SELECT
t.*,
STUFF((
SELECT distinct ',' + coalesce([txt], 'Unknown')
FROM #t t1
LEFT JOIN
#t2 x
ON x.sta = t1.STATUSES
WHERE t1.opportunityid = t.opportunityid
for xml path(''), type
).value('.', 'varchar(max)'), 1, 1, '') [status]
FROM cte t

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

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

sql puzzle sql server 2000

I have a small puzzle for myself.
PK is combination of lineNr and typeNr
i want to make a selection where all is_adres is N and the same for all linenrs, the same goes for is_postaddres. And I want the result in one view.
this is wat i want as end result
typenr,is_Adres ,is_postaddres
10, null , 'N'
11, 'N', null
13, 'N', 'N'
create table script + testdata
CREATE TABLE lineAdres
(
lineNr int,
typeNr int,
is_Adres char(1),
is_postaddres char(1)
);
INSERT INTO lineAdres VALUES
(1, 10,'J','N'),
(1, 11,'N','J'),
(1, 12,'N','J'),
(1, 13,'N','N'),
(2, 10,'J','N'),
(2, 11,'N','J'),
(2, 12,'J','N'),
(2, 13,'N','N');
I want to join this 2 views in one.. but how, and i got a feeling it could be more efficient!
select typenr, is_adres
from lineAdres
where is_adres = 'N'
group by typenr, is_adres
having count(*) = 2
select typenr, is_postaddres
from lineAdres
where is_postaddres = 'N'
group by typenr, is_postaddres
having count(*) = 2
To join the two result use a CTE and a full join to combine the data.
WITH IsAddress AS(
select typenr, is_adres
from lineAdres
where is_adres = 'N'
group by typenr, is_adres
having count(*) = 2),
IsPostAddress AS (select typenr, is_postaddres
from lineAdres
where is_postaddres = 'N'
group by typenr, is_postaddres
having count(*) = 2)
SELECT
COALESCE(IsAddress.typenr,IsPostAddress.typenr) typenr,
IsAddress.IsAddress,
IsPostAdress.is_postaddres
FROM
IsAddress
FULL OUTER JOIN
IsPostAdress
ON
IsAddress.typenr = IsPostAdress.typenr