SQL query help needed to include non matching records - sql

I have got a requirement to display a query which shows matching and non matching rows against the master lookup table
The #PostCodes table contains the postcodes for master table which the second query would be matched against
DECLARE #PostCodes TABLE
(
RowID int not null primary key identity(1,1),
Postcodes varchar(100)
)
SELECT
C.CampaignId, C.Name, C.Description,C.EndedOn, C.Active, C.Manager,
P.PostcodeArea, P.PostcodeDistrict
FROM
Campaign C, CampaignPostcode P, #PostCodes pc
WHERE
P.CampaignId = C.CampaignId AND
P.PostcodeDistrict = pc.Postcodes AND
C.EndedOn IS NULL
The second query returns me only the matching records against postcodes and I have tried everything to include unmatched records but no luck.
Any help?
EDIT (Tables)
PostCodes (table1) Campaign (table2)
Id Postcodes CampaignId Name Desc
1 AA 1 camp1 Desc1
2 AB 2 camp2 Desc2
3 AC 3 camp3 Desc3
4 AD 4 camp4 Desc4
CampaignPostcode (table3)
CampaignPostcodeId CampaignId PostcodeArea
1 1 AA
2 2 AB
3 2 AB
4 3 AC
Output Required
Id CampaignName Desc PostcodeIn PostcodeOut
1 Camp1 Desc1 AA NULL
2 Camp2 Desc2 AB NULL
3 Camp2 Desc2 AB NULL
4 Camp3 Desc3 AC NULL
5 Camp4 Desc4 NULL AD

What about this:
SELECT
C.CampaignId, C.Name, C.Description,C.EndedOn, C.Active, C.Manager,
P.PostcodeArea, P.PostcodeDistrict
FROM
Campaign C
INNER JOIN
CampaignPostcode P ON P.CampaignId = C.CampaignId
LEFT OUTER JOIN
#PostCodes pc ON P.PostcodeDistrict = pc.Postcodes
WHERE
C.EndedOn IS NULL

Try this instead:
SELECT
p.*
FROM #PostCodes AS PC
LEFT JOIN
(
SELECT *
FROM Campaign C
INNER JOIN CampaignPostcode P ON P.CampaignId = C.CampaignId
) AS p ON P.PostcodeDistrict = pc.Postcodes
WHERE P.EndedOn IS NULL

Related

SQL query doesnt return expected values

I have 3 tables. 1st table stores coil information, 2nd table store coil information in transport and 3rd stores reserved coils.
coils
ID
SERIAL
COLOR
MATERIAL
STATUS
1
12345
5
1
2
2
12346
4
1
3
3
12347
3
1
2
coils_in_transport
ID
SERIAL
COLOR
MATERIAL
STATUS
1
f34S5
5
1
2
2
A23GG6
4
1
3
3
ff2S147
3
1
2
reserved_coils
ID
NUMBER
QUANTITY
START
END
1
12345
25
2022-05-01
2023-05-01
3
12347
252
2022-01-01
2023-05-01
4
A23GG6
33
2022-04-01
2023-05-01
5
ff2S147
35
2022-08-01
2023-05-01
I need to write query that will get all reserved coils (reserved_coils) that has status 2 and for each coil I need to join tables for materials and colors
material
ID
NAME
1
color
ID
NAME
I wrote query but it doesn't show coils in transport that are reserved, here is what I tried
SELECT a.QUANTITY, a.START, a.END, b.name, m.name
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material b ON b.material = b.id
where b.status = 2 and c.status = 2
To get all coils and colis_in_transport you need to use UNION for SELECT statements for both tables, each filtered by status value, which should be equal to 2. Then you need to do a JOIN between reserved_coils and the result of UNION to filter out reserved_coils rows.
Your query would be like this
SELECT
r.quantity,
r.start,
r.[end],
c.serial,
material.name AS material,
color.name AS color
FROM reserved_coils r
JOIN (
SELECT * FROM coils WHERE status = 2
UNION
SELECT * FROM coils_in_transport WHERE status = 2
) c ON r.number = c.serial
LEFT JOIN material ON material.id = c.material
LEFT JOIN color ON color.id = c.color
Demo
If you want left join twice on same table, this might help
SELECT a.QUANTITY, a.START, a.[END], isnull(b.serial,c.serial) serial,isnull(c1.name,c2.name) color, isnull(m.name,n.name) material
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material n ON c.material = n.id
LEFT JOIN color c1 on b.color=c1.id
LEFT JOIN color c2 on c.color=c2.id
where isnull(b.status,c.status) = 2
DB<>Fiddle

Query to update all the null values to not null for all the columns in a single or dynamic query

I am looking for a SQL query to update all the columns in table A which has a NULL value to NOT NULL values from table C using reference as table B. All the columns in table A should be updated using a single query or dynamic query. Values should be updated based on column name and values should not be hard coded.
Table A
ID Name zip city Mdate
10001 Sarah NULL NULL 02-20-2018
98765 AJ NULL Ohio 01-15-2018
12345 NULL 7511 Texas 03-08-2018
Table B
ID RollNo Cdate
12345 1 01-18-2018
12345 2 01-22-2018
12345 3 03-20-2018
98765 9 01-18-2018
98765 8 01-22-2018
98765 7 03-20-2018
10001 10 03-08-2018
10001 11 01-15-2018
10001 12 02-20-2018
TABLE C
Rollno Name Zip City Mdate Cdate Modifyby
1 NULL 7511 Texas 01-18-2018 02-02-2017 #John
2 John 5001 NULL 01-22-2018 11-01-2017 #Krish
3 NULL 7000 Ohio 03-20-2018 11-15-2017 #Maria
10 Sarah NULL NULL 03-08-2018 10-05-2017 #tom
11 Tom NULL NULL 01-15-2018 04-05-2017 #Sony
12 NULL 5500 Pune 02-20-2018 03-25-2017 #Sandy
9 AJ NULL Ohio 01-18-2018 10-07-2017 #Mandy
8 NULL NULL NULL 01-12-2018 11-02-2017 #Deck
7 NUll 8000 NULL 01-12-2018 12-05-2017 #Ant
Output:
ID Name zip city Mdate Cdate Modifyby
10001 Sarah 5500 Pune 02-20-2018 03-25-2017 #Sandy
98765 AJ 8000 Ohio 01-18-2018 10-07-2017 #Mandy
12345 John 7511 Texas 03-08-2018 10-05-2017 #tom
In the output, all the NULL column values in table A are updated with NOT NULL values from table C. Please provide a single query to update all the NULL columns in a single query itself.
I am trying below query but unable to update the table with max Function. Is there any alternative for it.
Select * into #temp FROM
(
SELECT A.ID,
Row_number() over(partition by A.ID order by A.mdate desc) as
RNK,C.NAME,C.ZIP,C.CITY,C.MDate,C.Cdate,C.Modifyby
FROM tableA A
INNER JOIN tableB B ON A.ID = B.ID
INNER JOIN tableC C ON B.RollNo = C.RollNo
)X where RNK = 1
UPDATE A SET Name =
CASE
WHEN MAX(A.Name) IS NULL THEN MAX(C.Name)
ELSE Max(A.Name) END
, Zip =
CASE
WHEN MAX(A.Zip) IS NULL THEN Max(C.Zip)
ELSE MAX(A.Zip)
END ,
City =CASE
WHEN MAX(A.City) IS NULL THEN Max(C.City)
ELSE MAX(A.City)
END
FROM #temp A
INNER JOIN TableB B ON A.ID = B.ID
INNER JOIN tablec C ON B.RollNo = C.RollNo
Getting an error:
An aggregate may not appear in the set list of an UPDATE statement.
I need all the values in output table along with null values updated with not null values.
Try this below script-
DEMO HERE
SELECT A.ID,
CASE
WHEN MAX(A.Name) IS NULL THEN MAX(C.Name)
ELSE Max(A.Name)
END Name,
CASE
WHEN MAX(A.Zip) IS NULL THEN Max(C.Zip)
ELSE MAX(A.Zip)
END Zip,
CASE
WHEN MAX(A.City) IS NULL THEN Max(C.City)
ELSE MAX(A.City)
END City,
A.MDate
FROM table_a A
INNER JOIN Table_B B ON A.ID = B.ID
INNER JOIN table_c C ON B.RollNo = C.RollNo
GROUP BY A.ID,A.MDate

SQL Query Left Outer Join To Current Query

I have a query and I want to look up the values from other table as a reference but not mess up my current query results. I think I have to use a Outer Left Join, but not sure how to incorporate that with my current query.
My current query looks similar to this:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH,
d.color
FROM TableA a,
TableB b,
TableC c,
TableD d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date IS NULL OR c.number IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1
Now, that gives me a table of 50 results. 'TableContacts' has the look up value to my b.project_number. So say my table of 50 results, only 10 of them have b.project_number, I need the lookup values from 'TableContacts' to also show in my results, but I don't want that to affect my results and cut it down to 10, I still need my original 50 results, just with that additional information. Help?
Just add the CONTACTS table to your joins:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH,
d.color,
ct.lookup_value --<< this is from the CONTACTS table
FROM TableA a
JOIN TableB b ON b.primary_key = a.PROJECT_ID
JOIN TableC c ON c.primary_key = a.PROJECT_ID
JOIN TableD d ON b.primary_key = d.project_ID
LEFT JOIN contacts ct ON ct.some_column = b.project_Number --<< this is the outer join to the CONTACTS table
WHERE (c.date IS NULL OR c.number IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1
As you obfuscated your table and column names it's hard to guess how exactly the join condition on the CONTACTS table should look like.
You could use this approach:
Create a table with the results of your current query:
create table t1 as
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH_col,
d.color
FROM a,b,c,d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date_col IS NULL OR c.number_col IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1;
Use a union to get the desired results:
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, TableContacts.lookup_column
from t1, TableContacts
where t1.project_number = TableContacts.project_number
UNION
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, null
from t1 where t1.project_number is null;
Illustration by creating dummy data:
select * from a;
PRIMARY_KEY | PROJECT_ID | PHASE
1 100 Phase-1
2 200 Phase-2
3 300 Phase-3
4 400 Phase-4
5 500 Phase-5
select * from b;
PRIMARY_KEY | PROJECT_NUMBER
100 null
200 2000
300 3000
400 null
500 5000
select * from c;
PRIMARY_KEY | NUMBER_COL | LENGTH_COL | DATE_COL
100 null 99 null
200 null 99 null
300 null 99 null
400 null 99 null
500 null 99 null
select * from d;
PROJECT_ID | COLOR
100 black
200 red
300 blue
400 black
500 yellow
select * from TableContacts;
PROJECT_NUMBER | LOOKUP_COLUMN
1000 l-1000
2000 l-2000
3000 l-3000
4000 l-4000
5000 l-5000
Existing query in question returns this:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH_col,
d.color
FROM a,b,c,d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date_col IS NULL OR c.number_col IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1;
PRIMARY_KEY | PHASE | PROJECT_NUMBER | LENGTH_COL | COLOR
1 Phase-1 null 99 black
2 Phase-2 2000 99 red
3 Phase-3 3000 99 blue
4 Phase-4 null 99 black
The goal is to populate the lookup_column where project_number is not null. Running the union query provided at start of answer:
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, TableContacts.lookup_column
from t1, TableContacts
where t1.project_number = TableContacts.project_number
UNION
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, null
from t1 where t1.project_number is null;
PRIMARY_KEY | PHASE | PROJECT_NUMBER | LENGTH_COL | COLOR | LOOKUP_COLUMN
1 Phase-1 null 99 black null
2 Phase-2 2000 99 red l-2000
3 Phase-3 3000 99 blue l-3000
4 Phase-4 null 99 black null

How to get unique records in the SQL Server 2000

I have 4 tables
Table1 : Employeetab
Employeeid EmployeeName
1 xyz
2 abc
3 mno
4 pqr
Table2 : PurchaseRequesttab
PRID Employeeid PRNR
1 1 pr1
Table3 : Statustab
StatusID Statusmsg
1 approve by manager
2 approve by CC manager
3 approve by designer
4 approve by BU head
Table4 : ApprovalStatustab
PRID StatusID Employeeid ApprovalDate
1 1 3 jan 1 2015
1 2 3 jan 3 2015
1 4 4 Jan 5 2015
Result should be
PRNR EmployeeName Statusmsg
pr1 mno approve by CC manager
Below is my query, which gives duplicate
Select
distinct P.PRNR, EmployeeName, Statusmsg
from Employeetab as E
inner join PurchaseRequesttab AS P ON E. Employeeid = p.Employeeid
inner join ApprovalStatustab as A ON P. PRID = A. PRID
inner join Statustab as S on A. StatusID = S. StatusID
How to get unique records in the result set, edited the result :)
Some thing your data is mismatch with your entry and your table structure.
1. ApprovalStatustab A and PurchaseRequesttab as P - P.PRID = A.PRID mismatch entry as above.
Here is your sample query below, I comment and add some entry for better understand what you doing wrong.
declare #Employeetab table(Employeeid int, EmployeeName varchar(50))
declare #PurchaseRequesttab table(PRID int,Employeeid int, PRNR varchar(50) )
declare #Statustab table(StatusID int, Statusmsg varchar(50) )
declare #ApprovalStatustab table(PRID int, StatusID int, Employeeid int, ApprovalDate varchar(50) )
insert into #Employeetab values (1,'xyz'),(2,'abc'),(3,'mno'),(4,'pqr')
insert into #PurchaseRequesttab values (1,1,'pr1')
, (2,3,'pr3') --this I added to get the result
insert into #Statustab values (1,'approve by manager'),(2,'approve by CC manager'),(3,'approve by designer'),(4,'approve by BU head')
insert into #ApprovalStatustab values (1,1,3,'jan 1 2015'),(1,2,3,'jan 3 2015'),(1,4,4,'jan 5 2015')
,(2,2,3,'jan 5 2015') --this I added to get the result
Select
distinct
P.PRNR,
EmployeeName
,Statusmsg
from #Employeetab as E
inner join #PurchaseRequesttab AS P ON E.Employeeid = p.Employeeid
inner join #ApprovalStatustab as A ON P.PRID = A.PRID
--and a.Employeeid = e.Employeeid --this is added for distinct result too
inner join #Statustab as S on A.StatusID = S.StatusID
Your status msg has to be different because your status id is different and they have different messages... if they had the same message you would have 1 row.
Ensure the column PRNR in PurchaseRequesttab is unique (like PRID column).

Get the max value of a column from set of rows

I have a table like this
Table A:
Id Count
1 4
1 16
1 8
2 10
2 15
3 18
etc
Table B:
1 sample1.file
2 sample2.file
3 sample3.file
TABLE C:
Count fileNumber
16 1234
4 2345
15 3456
18 4567
and so on...
What I want is this
1 sample1.file 1234
2 sample2.file 3456
3 sample3.file 4567
To get the max value from table A I used
Select MAX (Count) from A where Id='1'
This works well but my problem is when combining data with another table.
When I join Table B and Table A, I need to get the MAX for all Ids and in my query I dont know what Id is.
This is my query
SELECT B.*,C.*
JOIN A on A.Id = B.ID
JOIN C on A.id = B.ID
WHERE (SELECT MAX(COUNT)
FROM A
WHERE Id = <what goes here????>)
To summarise, what I want is Values from Table B, FileNumber from Table c (where the count is Max for ID from table A).
UPDATE: COrrecting table C above. Looks like I need Table A.
I think this is the query you're looking for:
select b.*, c.filenumber from b
join (
select id, max(count) as count from a
group by id
) as NewA on b.id = NewA.id
join c on NewA.count = c.count
However, you should take into account that I don't get why for id=1 in tableA you choose the 16 to match against table C (which is the max) and for id=2 in tableA you choose the 10 to match against table C (which is the min). I assumed you meant the max in both cases.
Edit:
I see you've updated tableA data. The query results in this, given the previous data:
+----+---------------+------------+
| ID | FILENAME | FILENUMBER |
+----+---------------+------------+
| 1 | sample1.file | 1234 |
| 2 | sample2.file | 3456 |
| 3 | sample3.file | 4567 |
+----+---------------+------------+
Here is a working example
Using Mosty’s working example (renaming the keyword count to cnt for a column name), this is another approach:
with abc as (
select
a.id,
a.cnt,
rank() over (
partition by a.id
order by cnt desc
) as rk,
b.filename
from a join b on a.id = b.id
)
select
abc.id, abc.filename, c.filenumber
from abc join c
on c.cnt = abc.cnt
where rk = 1;
select
PreMax.ID,
B.FileName,
C2.FileNumber
from
( select C.id, max( C.count ) maxPerID
from TableC C
group by C.ID
order by C.ID ) PreMax
JOIN TableC C2
on PreMax.ID = C2.ID
AND PreMax.maxPerID = C2.Count
JOIN TableB B
on PreMax.ID = B.ID