Fill columns which have priority over other columns in SQL Server - sql-server

I have a table like this:
id
mail_1
mail_2
mail_3
1
john
john_v2
john_v3
2
clarisse
NULL
clarisse_company
3
NULL
julie
NULL
4
mark
markus_91
NULL
5
alfred
NULL
NULL
And I would like to achieve that:
id
mail_1
mail_2
mail_3
1
john
john_v2
john_v3
2
clarisse
clarisse_company
NULL
3
julie
NULL
NULL
4
mark
markus_91
NULL
5
alfred
NULL
NULL
As you can see, if mail_2 or mail_3 are not null and mail_1 is null, mail_1 should be fulfilled. The thing here is if the id has two mails, this two mails must be in mail_1 and mail_2, not in mail_2 and mail_3 nor mail_1 and mail_3. If an id has just one mail, this mail must be in mail_1.
So the logic here is that mail_1 has priority over the other two, and mail_2 has priority over mail_3.
How could I achieve that in SQL Server (version 15)?

This should do. Just play by changing the values of the table variable below
declare #temp table(mail_1 varchar(20),mail_2 varchar(20),mail_3 varchar(20))
insert into #temp values(null,'middlename','lastname')
select coalesce(mail_1,mail_2,mail_3) as mail_1,
case when mail_1
is null and mail_2 is not null then mail_3
when mail_1
is not null and mail_2 is null
then
mail_3
else mail_2 end mail_2,
case when (mail_1 is null or mail_2 is null) then null else mail_3 end mail_3
from #temp

Related

Need help in rewriting the query using CASE statement

SELECT distinct
ID,
LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id)) as pos
FROM table1
WHERE date='2022-02-02'
AND pos_id is not null
AND id='12345';
When I run the above query, I'm getting results like
ID
POS
12345
894f4bb2597f
But when I run the query below where I have used CASE, I'm getting NULL values as well as NOT NULL values.
SELECT distinct
ID,
CASE WHEN REGEXP_COUNT(pos_id, '^[0-9]+$')= 1 AND pos_id IS NOT NULL THEN NULL ELSE pos_id
END as pos
FROM table1
WHERE date='2022-02-02'
AND pos_id is not null
AND id='12345';
ID
POS
12345
894f4bb2597f
12345
NULL
For one ID, I'm getting NULL as well not NULL values.
I need to remove pos_id is not null in the WHERE clause and add that in CASE statement.
How to rewrite this query using CASE statement by removing the condition - pos_id is not null from the WHERE clause?
I tried the below query using CASE statement but not getting the correct results:
SELECT distinct
ID,
CASE when REGEXP_COUNT(pos_id,'^[0-9]+$')=1 and
pos_id is not null
THEN null else pos_id end
FROM table1
WHERE date='2022-02-02';
When I use CASE, I'm getting the count as 1,455,345 ROWS
but when I use - LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id
I'm getting COUNT as 2768 rows
so the key point of you question is the final sentence:
When I use CASE, I'm getting the count as 1,455,345 ROWS but when I use - LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id I'm getting COUNT as 2768 rows
So take your SQL and pushing it together with some input trying to understand "why the results are different" etc etc.
And really you are asking why do I how more distinct values when I don't to lower then then when I do.
The point is case sensitive counts will always be same or great than case insensitive counts.
SELECT
column2 as pos_id,
LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id)) as pos_i,
CASE
WHEN REGEXP_COUNT(pos_id, '^[0-9]+$') = 1 AND pos_id IS NOT NULL THEN NULL
ELSE pos_id
END as pos_c
,lower(pos_c) as lower_pos_c
,count(distinct pos_i) over() as IFF_rows_count
,count(distinct pos_c) over() as CASE_rows_count
,count(distinct lower_pos_c) over() as LOWER_CASE_rows_count
FROM VALUES
(12345, '894f4bb2597f'),
(12346, '1234'),
(12346, null),
(123, 'aaa'),
(123, 'Aaa'),
(123, 'aAa'),
(123, 'aaA');
POS_ID
POS_I
POS_C
LOWER_POS_C
IFF_ROWS_COUNT
CASE_ROWS_COUNT
LOWER_CASE_ROWS_COUNT
894f4bb2597f
894f4bb2597f
894f4bb2597f
894f4bb2597f
2
5
2
1234
null
null
null
2
5
2
null
null
null
null
2
5
2
aaa
aaa
aaa
aaa
2
5
2
Aaa
aaa
Aaa
aaa
2
5
2
aAa
aaa
aAa
aaa
2
5
2
aaA
aaa
aaA
aaa
2
5
2

SQL Check to see if any value in a list exists in another table

I have a temp table that looks something like this:
Record DepartmentId PositionId EmployeeId StatusId CustomerId
1 Null Null Null 4
2 7 454 Null Null
3 Null 454 Null 3
3 Null Null Null Null 214
3 Null Null Null Null 100
3 Null Null Null Null 312
4 Null Null Null Null 357
I inserted the above into the temp table from tables that looked like this:
Record Table Record-to-Department Record-to-Position
Record Name Record DepartmentId Record PositionId
1 Red 2 7 2 454
2 blue 3 454
3 Green
4 Purple
Record-To-Status Record-To-Customer
Record StatusId Record CustomerId
1 4 3 214
3 3 3 100
3 312
4 357
I have an employee whose record looks something like this:
EmployeeId DepartmentId PositionId StatusId
342 7 454 4
Employee Customers:
EmployeeId CustomerId
342 357
342 95
342 720
In this scenario, it would return Record 1 (because it matches the StatusId), Record 2 (because it matches both the DepartmentId and the PositionId), but it would not return Record 3 because it only matches the PositionId and not the StatusId, and it would return RecordId 4 because one of the Employee CustomerIds matches the CustomerId on Record 4.
I got part of this answer on another question enter link description here (please forgive me I am new and trying to figure out how to ask everything I need to know), but I can't figure out how to handle the multi-records.
I tried selecting the Employees customer Id's into a table variable and then attempted to use the Coalesce like this:
Declare #Customers table(CustomerId int)
INSERT INTO #Customers(CustomerId)
SELECT DISTINCT S.CustomerId
FROM employee_Customers
Select * from tbl
WHERE
COAlesce(StatusId,#StatusId)=#StatusId AND
COALESCE(DepartmentId,#DepartmentId)=#DepartmentId AND
Coalesce(PositionId,#PositionId)=#PositionId AND
Coalesce(EmployeeCompanyId,#EmployeeCompanyId) = #EmployeeCompanyId AND
COALESCE((Select CustomerId from tbl_Requirement_to_Customer),(Select CustomerId from #Customers)) = (Select CustomerId from #Customers)
But I receive the error "Subquery Returned more than 1 value".
I have a possible solution you can try. I don't think it will be plug-and-play but hopefully you can adapt it to your situation. I am using just the data as presented in your temp table, your employee record and your Employee-customers correlation.
The basic logic is to join your temp table to the employee(s) using or condition, but then to get a count of populated values, and compare this count to a count of the number of matching values, which must be at least the first count and greater than zero.
This returns your desired output:
select t.*
from Temp t
left join emp e on e.DepartmentId=t.DepartmentId or e.PositionId=t.PositionId or e.EmployeeId=t.EmployeeId or e.StatusId=t.StatusId
outer apply (
select case when exists (
select * from EmployeeCustomers ec join emp e on e.EmployeeId=ec.EmployeeId where ec.CustomerID=t.CustomerId
) then 1 else 0 end CustomerIdMatch
)c
outer apply (
values (
Iif(t.departmentId is null,0,1) +
Iif(t.PositionId is null,0,1) +
Iif(t.EmployeeId is null,0,1) +
Iif(t.StatusId is null,0,1) +
c.CustomerIdMatch
))x(Cnt)
outer apply (
values (
Iif(t.departmentId=e.DepartmentId,1,0) +
Iif(t.PositionId=e.PositionId,1,0) +
Iif(t.EmployeeId=e.EmployeeId,1,0) +
Iif(t.StatusId=e.StatusId,1,0) +
c.CustomerIdMatch
))y(Cnt2)
where cnt2>=cnt and cnt2>0
See working DB<>Fiddle

T-SQL Get Values from Lookup table and use in view / stored procedure

I couldn't find that via search, so I guess I am not asking it the right way, so help is welcome.
We have a lookup table:
Id Name
------------------
1 "Test"
2 "New"
3 "InProgress"
Table2:
StatusId SomethingElse
1
2
Table 1
ID Other Other StatusId (Fkey to Table2) ...
Then we have a view that selects from several tables and one of the columns is a CASE Statement:
SELECT * FROM Table1 t1 -- has million records
CASE When t1.StatusId = 1 THEN (SELECT Name from LOOKUP table where ID = 1) END --'Test'
CASE When t1.StatusId = 2 THEN (SELECT Name from LOOKUP table where ID = 2) END --'New'
CASE When t3.Date is not null THEN (SELECT Name from LOOKUP table where ID = 3) END --'In Progress'
-- AND ALSO the case look at other tables another 5-6 tables and there are conditions from there
INNER JOIN Table2 t2 on ...
INNER JOIN Table3 t3 on ...
As you see these are really static values.
I want to load them once into variables, e.g.
#LookUp1 = SELECT [NAME] FROM LookUP WHERE Id = 1,
#LookUp2 = SELECT [NAME] FROM LookUP WHERE Id = 2
and replace the select in the CASE statement to this:
When StatusId = 1 THEN #LookUp
When StatusId = 2 THEN #LookUp2
The view loops through millions of records and it gets really slow to do the select from Lookup table for every row.
Why not simply use a join?
SELECT <columns list from main table>, Lt.Name
FROM <main table> As Mt -- Do not use such aliases in real code!
JOIN <SecondaryTable> As St -- this represents your Table3
ON <condition>
[LEFT] JOIN <Lookup table> As Lt
ON Mt.StatusId = Lt.Id
OR (Lt.Id = 3 AND St.Date is not null)
Of course, replace <columns list from main table> with the actual columns list, <main table> with the name of the main table and so on.
The join might be an inner or left join, depending on the nullability of the StatusId column in the main table and if it's nullable, on what you want to get in such cases (either a row with null name or no row at all).
I've put together a little demonstration to show you exactly what I mean.
Create and populate sample tables (Please save us this step in your future questions):
CREATE TABLE LookUp (Id int, Name varchar(10));
INSERT INTO LookUp (Id, Name) VALUES
(1, 'Test'), (2, 'New'), (3, 'InProgress');
CREATE TABLE Table1 (Id int not null, StatusId int null);
INSERT INTO Table1(Id, StatusId)
SELECT n, CASE WHEN n % 3 = 0 THEN NULL ELSE (n % 3) END
FROM
(
SELECT TOP 30 ROW_NUMBER() OVER(ORDER BY ##SPID) As n
FROM sys.objects
) tally
CREATE TABLE Table3
(
Id int not null,
Date date null
)
INSERT INTO Table3 (Id, Date)
SELECT Id, CASE WHEN StatusId IS NULL AND Id % 4 = 0 THEN GetDate() END
FROM Table1
The query:
SELECT Table1.Id,
Table1.StatusId,
Table3.Date,
LookUp.Name
FROM Table1
JOIN Table3
ON Table1.Id = Table3.Id
LEFT JOIN LookUp
ON Table1.StatusId = LookUp.Id
OR (LookUp.Id = 3 AND Table3.Date IS NOT NULL)
Results:
Id StatusId Date Name
1 1 NULL Test
2 2 NULL New
3 NULL NULL NULL
4 1 NULL Test
5 2 NULL New
6 NULL NULL NULL
7 1 NULL Test
8 2 NULL New
9 NULL NULL NULL
10 1 NULL Test
11 2 NULL New
12 NULL 27.06.2019 InProgress
13 1 NULL Test
14 2 NULL New
15 NULL NULL NULL
16 1 NULL Test
17 2 NULL New
18 NULL NULL NULL
19 1 NULL Test
20 2 NULL New
21 NULL NULL NULL
22 1 NULL Test
23 2 NULL New
24 NULL 27.06.2019 InProgress
25 1 NULL Test
26 2 NULL New
27 NULL NULL NULL
28 1 NULL Test
29 2 NULL New
30 NULL NULL NULL
You can also see a live demo on rextester.
Create a SQL function which return Name according to Id.
Create FUNCTION [dbo].[GetLookUpValue]
(
#Id int
)
RETURNS varchar(500)
AS BEGIN
return(Select Name from LOOKUP_table with(nolock) where Id=#Id)
END

deleting duplicates based on value of another column

I have a table with 3 columns and the first column is 'name'. Some names are entered twice, some 3 times and some more than that. I would like to keep only one value for each name and delete the extra rows based on the values of Column 2 and 3. If column 2 and 3 are null, I would like to delete that row.
There are no primary keys or id column.
There are about 2.75 million rows in the table.
Would like to delete using one query(preferably) in SQL 14. Can someone help please?
Name column2 column3
Suzy english null
Suzy null null
Suzy null 5
John null null
John 7 7
George null benson
George null null
George benson null
George 5 benson
Would like to have it as:
Name column2 column3
Suzy english null
Suzy null 5
John 7 7
George benson null
George 5 benson
Many thanks in advance.
Use partitions over name with the appropriate order by:
WITH cte as (
SELECT ROW_NUMBER()
OVER (PARTITION BY name
ORDER BY case
when column1 = 'null' and column2 = 'null' then 3
when column2 = 'null' then 2
when column1 = 'null' then 1
else 0 end
) num
FROM mytable
)
delete from cte where num > 1
This deletes duplicates, keeping in order of preference, rows with:
both column1 and column2 not null (random one kept if there are multiple of these)
column1 not null
column2 not null
both column1 and column2 null
Note that is query assumes (based on comments to question) that your "null" values are actually the text string "null" and not an SQL null.
If they were actually nulls, replace = 'null' with IS NULL.
Delete from yourtable
where column2 is null and column3 is null
above query is Based on this..
I would like to keep only one value for each name and delete the extra rows based on the values of Column 2 and 3. If column 2 and 3 are null, I would like to delete that row

SQL Server pivot using case statement

I'm trying to pivot out some data and I think I need to incorporate a case statement in my pivot code but I'm not sure how. I have the table below:
ID AreaCode
1001 1501
1001 1502
1001 2301
1031 1010
1031 3012
1048 2304
1048 3012
1048 4022
The first digit of each AreaCode refers to a body area, I'm using the code below to indicate which body area is affected:
select id,
case when left(areaID,1)=1 then 'Yes' end Head,
case when left(areaID,1)=2 then 'Yes' end Face,
case when left(areaID,1)=3 then 'Yes' end Neck,
case when left(areaID,1)=4 then 'Yes' end Abdo
from #testcase
Which gives me the following:
id Head Face Neck Abdo
1001 Yes NULL NULL NULL
1001 Yes NULL NULL NULL
1001 NULL Yes NULL NULL
1031 Yes NULL NULL NULL
1031 NULL NULL Yes NULL
1048 NULL Yes NULL NULL
1048 NULL NULL Yes NULL
1048 NULL NULL NULL Yes
However, I need my output table to contain one row for each id, like so:
id Head Face Neck Abdo
1001 Yes Yes Null Null
1031 Yes Null Yes Null
1048 Null Yes Yes Yes
Can incorporate my case statement in a pivot to achieve this? Thanks
You need to use aggregate on top of case statements
SELECT id,
Max(CASE
WHEN LEFT(areaID, 1) = 1 THEN 'Yes'
END) Head,
Max(CASE
WHEN LEFT(areaID, 1) = 2 THEN 'Yes'
END) Face,
Max(CASE
WHEN LEFT(areaID, 1) = 3 THEN 'Yes'
END) Neck,
Max(CASE
WHEN LEFT(areaID, 1) = 4 THEN 'Yes'
END) Abdo
FROM #testcase
GROUP BY id
You could use a real PIVOT solution instead like this:
DECLARE #t table(ID int, AreaCode int)
INSERT #t
VALUES
(1001,1501),(1001,1502),(1001,2301),(1031,1010),
(1031,3012),(1048,2304),(1048,3012),(1048,4022)
SELECT id, [1]Head, [2]Face, [3]Neck, [4]Abdo
FROM
(
SELECT id, left(AreaCode, 1) Area, 'Yes' x
FROM #t
) p
PIVOT (Max(x) FOR [Area] IN ([1],[2],[3],[4])) AS pvt
Result:
id Head Face Neck Abdo
1001 Yes Yes NULL NULL
1031 Yes NULL Yes NULL
1048 NULL Yes Yes Yes

Resources