Related
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 '
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
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
I want to create a Y/N flag, where Y indicates every valid value in every column in a given row is equal, and N otherwise. I need to exclude from consideration any column that contains nulls, blanks, or all zeroes. Suppose:
CREATE TABLE z_test
(ID INT NOT NULL,
D1 VARCHAR(8)NULL,
D2 VARCHAR(8)NULL,
D3 VARCHAR(8)NULL,
D4 VARCHAR(8)NULL,
DFLAG CHAR(1)NULL)
INSERT INTO z_test VALUES (1,NULL,' ','000000','00000000',NULL)
INSERT INTO z_test VALUES (1,'20120101','0000','20120101','00000000',NULL)
INSERT INTO z_test VALUES (2,'20100101','20100101','20100101','20100101',NULL)
INSERT INTO z_test VALUES (2,'00000000','20090101','0','20090101',NULL)
INSERT INTO z_test VALUES (3,'00000000','20090101',NULL,'20120101',NULL)
INSERT INTO z_test VALUES (3,'20100101',' ',NULL,'20100101',NULL)
The desired output (excluding D1 through D4, though I don't want to drop them) is:
ID DFLAG
---------------
1 N
1 Y
2 Y
2 Y
3 N
3 Y
Speed is not a concern as this query will not be run very often but it is on a largish table.
Any pointers or suggestions would be very much appreciated!!
SELECT ID,
CASE
WHEN C = 1 THEN 'Y'
ELSE 'N'
END AS DFLAG
FROM z_test
CROSS APPLY (SELECT COUNT(DISTINCT D) C
FROM (VALUES(D1),
(D2),
(D3),
(D4)) V(D)
WHERE LEN(D) > 0 /*Excludes blanks and NULLs*/
AND D LIKE '%[^0]%'/*Excludes ones with only zero*/) CA
This works:
select case when
(D1 is null OR D2 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D2,'0',''))=0 OR D1=D2)
AND (D1 is null OR D3 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D3,'0',''))=0 OR D1=D3)
AND (D1 is null OR D4 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D1=D4)
AND (D2 is null OR D3 is null OR LEN(REPLACE(D2,'0',''))=0 OR LEN(REPLACE(D3,'0',''))=0 OR D2=D3)
AND (D2 is null OR D4 is null OR LEN(REPLACE(D2,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D2=D4)
AND (D3 is null OR D4 is null OR LEN(REPLACE(D3,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D3=D4)
AND (LEN(REPLACE(D1,'0','')) > 0
OR LEN(REPLACE(D2,'0','')) > 0
OR LEN(REPLACE(D3,'0','')) > 0
OR LEN(REPLACE(D4,'0','')) > 0)
THEN 'Y' ELSE 'N' END
from z_test
Here is the link to sqlfiddle.
try this:
DECLARE #z_test table
(ID INT NOT NULL,
D1 VARCHAR(8)NULL,
D2 VARCHAR(8)NULL,
D3 VARCHAR(8)NULL,
D4 VARCHAR(8)NULL,
DFLAG CHAR(1)NULL)
INSERT INTO #z_test VALUES (1,NULL,' ','000000','00000000',NULL)
INSERT INTO #z_test VALUES (1,'20120101','0000','20120101','00000000',NULL)
INSERT INTO #z_test VALUES (2,'20100101','20100101','20100101','20100101',NULL)
INSERT INTO #z_test VALUES (2,'00000000','20090101','0','20090101',NULL)
INSERT INTO #z_test VALUES (3,'00000000','20090101',NULL,'20120101',NULL)
INSERT INTO #z_test VALUES (3,'20100101',' ',NULL,'20100101',NULL)
;WITH Fixed AS
(SELECT --converts columns with all zeros and any spaces to NULL
ID
,NULLIF(NULLIF(D1,''),0) AS D1
,NULLIF(NULLIF(D2,''),0) AS D2
,NULLIF(NULLIF(D3,''),0) AS D3
,NULLIF(NULLIF(D4,''),0) AS D4
FROM #z_test
)
SELECT --final result set
ID,
CASE
WHEN COALESCE(D1,D2,D3,D4) IS NULL THEN 'N' --all columns null
WHEN (D1 IS NULL OR D1=COALESCE(D1,D2,D3,D4)) --all columns either null or the same
AND (D2 IS NULL OR D2=COALESCE(D1,D2,D3,D4))
AND (D3 IS NULL OR D3=COALESCE(D1,D2,D3,D4))
AND (D4 IS NULL OR D4=COALESCE(D1,D2,D3,D4))
THEN 'Y'
ELSE 'N'
END
FROM Fixed
OUTPUT:
ID
----------- ----
1 N
1 Y
2 Y
2 Y
3 N
3 Y
(6 row(s) affected)
You can create a function for this.
create function fnRowValid(#d1 varchar, #d2 varchar...)
returns bit ------ 1 for true and 0 for false
begin
declare table #validvalue (val varchar)
if isdate(d1) = 0 and isdate(d1) = 0 and ...
return 0
if isdate(#d1)
insert into #validvalue (val) values (#d1)
if isdate(#d2)
insert into #validvalue (val) values (#d2)
if isdate(#d3)
insert into #validvalue (val) values (#d3)
...
if exists (select 1 from #validvalue)
if (select count(distinct val) from #validvalue) = 1
return 1
return 0
end
Then you can use this in the update statement...
update z_test
set dflag = dbo.fnRowValid(d1,d2,d3..)
Please don't flame me for this... I didn't test this code obviously. And this is the first solution that popped into my head... not a real elegant but should work. I'm not positive you can use table variables in a function either. Sorry about the ugly solution.
With RnkSource As
(
Select Id, D1, D2, D3, D4, DFlag
, Row_Number() Over ( Order By Id ) As RowNum
From z_test
)
, Source As
(
Select RowNum, Id, 'D1' As Col, D1 As Val
From RnkSource
Union All
Select RowNum, Id, 'D2', D2
From RnkSource
Union All
Select RowNum, Id, 'D3', D3
From RnkSource
Union All
Select RowNum, Id, 'D4', D4
From RnkSource
)
Select Id
, Case When Count(*) = 4 Then 'Y' Else 'N' End As DFLAG
From Source As S
Where Len(Val) > 0
Group By RowNum, Id
SQL Fiddle version
How can I do with SQL Server to get a single row where the only non-null values are the ones that are consistent and non-null through all the selected rows.
A B C D
10 NULL text NULL
4 abc text NULL
4 def text NULL
Should give the following row:
A B C D
NULL NULL text NULL
create table #t (col1 int, col2 char(3), col3 char(4), col4 int)
go
insert into #t select 10, null, 'text', null
insert into #t select 4, 'abc', 'text', null
insert into #t select 4, 'def', 'text', null
go
select
case when count(distinct isnull(col1, 0)) > 1 then null else max(col1) end as 'col1',
case when count(distinct isnull(col2, '')) > 1 then null else max(col2) end as 'col2',
case when count(distinct isnull(col3, '')) > 1 then null else max(col3) end as 'col3',
case when count(distinct isnull(col4, 0)) > 1 then null else max(col4) end as 'col4'
from
#t
go
drop table #t
go
EDIT: I added ISNULL to handle the issue identified by t-clausen.dk but this will only work if the 'default' values (i.e. zero and empty string) do not appear in the real data.
Daniel's comment about data types is also correct, but since we don't know the data types involved it's not easy to suggest an alternative. Providing a self-contained test script that uses the real data types is the best way to ask questions like this.
declare #t table(A int, b varchar(10), c varchar(max), d int)
insert #t values(10, null, 'text', null)
insert #t values(4, 'abc', 'text', null)
insert #t values(10, 'def', 'text', null)
select case when max(rna) > 1 then null else min(a) end,
case when max(rnb) > 1 then null else min(b) end,
case when max(rnc) > 1 then null else min(c) end,
case when max(rnd) > 1 then null else min(d) end
from
(
select rna = rank() over(order by a),
rnb = rank() over(order by b),
rnc = rank() over(order by c),
rnd = rank() over(order by d),
a, b,c,d
from #t
) e
If you have text columns replace the column type with varchar(max). Text columns are outdated.
Using count(distinct col1) was by first thought, but it doesn't count null values.
select count(distinct a) from (select cast(null as int) a) b
returns 0 rows
SELECT
CASE WHEN COUNT(DISTINCT col1) = 1
AND COUNT(col1) = COUNT(*)
THEN MIN(col1)
END AS col1
, CASE WHEN COUNT(DISTINCT col2) = 1
AND COUNT(col2) = COUNT(*)
THEN MIN(col2)
END AS col2
, CASE WHEN COUNT(DISTINCT col3) = 1
AND COUNT(col3) = COUNT(*)
THEN MIN(col3)
END AS col3
, CASE WHEN COUNT(DISTINCT col4) = 1
AND COUNT(col4) = COUNT(*)
THEN MIN(col4)
END AS col4
FROM
tableX