SQL query- help in implementation - sql

I have two tables: Member and Document
Member table:
Memberkey(Key) Member country
-------------- ---------------
111 Aus
222 US
333 Germany
444 Chile
Document table:
Memberkey(notNULL) doc_type_cd doc_cat_cd docname
---------------- ----------- ---------- -------------
111 1 1 Sales_doc
222 2 1 Finance_doc
222 3 3 Legal_doc
333 3 3 Legal_doc
444 2 1 Finance doc
444 3 3 Legal_doc
My requirement is to fetch memberkey, member country, and doc_name only if the document is legal_doc (i.e. doc_type_cd = 3 and doc_cat_cd =3). If no such document exists for a member, then this should come as null.
Output:
Memberkey member country doc_name
---------- -------------- -----------
111 aus NULL
222 US Legal_doc
333 Germany Legal_doc
444 Chile Legal_doc
How can I achieve this? If I use condition on doc_type_cd and doc_cat_cd in the query, then those members will be skipped, who have no legal_doc (111 in this example). Also, if a member has no entry in "document" table, then it should also be shown with member key, country and documentname(NULL in this case). Is there any effcient way to achieve this?
Please help. Thanks!

You need a left join for your requirement. By left joining on the three conditions below you will get a record for every member, and if they do have a legal document than that will be populated in the doc_name column, and if they do not have a legal document than the value will be null.
SELECT M.MemberKey, M.[member country], D.doc_name
FROM Member M
LEFT JOIN Document D ON
M.MemberKey = D.MemberKey AND
D.doc_type_cd = 3 AND
D.doc_cat_cd = 3

Here is a solution in MSSQL:
SELECT
M.MemberKey
, M.MemberCountry
, DCA.DocName
FROM
[Member] M
OUTER APPLY (
SELECT
D.DocName
FROM
[Document] D
WHERE
D.MemberKey = M.MemberKey
AND D.doc_type_cd = 3
AND D.doc_cat_cd =3
) DCA
Please note, that this query will retrieve multiple rows if there are multiple legal documents. If you want to get the first document, add TOP(1) to the subquery.

You want to use a case statement, and test for doc_type_cd or doc_cat_cd, like this:
select memberkey,
[member country],
case when doc_type_cd = 3 or doc_cat_cd = 3 then doc_name else null end
from memberTable mt
left outer join documentTable dt
on mt.memberKey = dt.memberKey

Here is another solution which could run on most RDBMS:
-- Query to get all members with legal document
SELECT
M.MemberKey
, M.MemberCountry
, D.DocName
FROM
Member M
INNER JOIN Document D
ON M.MemberKey = D.MemberKey
WHERE
D.doc_type_cd = 3
AND D.doc_cat_cd =3
UNION ALL
-- Query to get all members without legal document
SELECT
M.MemberKey
, M.MemberCountry
, NULL AS DocName
FROM
Member M
WHERE
NOT EXISTS (SELECT 1 FROM Document D WHERE D.MemberKey = M.MemberKey AND D.doc_type_cd = 3 AND D.doc_cat_cd = 3)

Related

Select from table 1 unless there is a relationship in 2 other tables

I need to query a name(s) from the Officials table, but exclude that name if the person has the day blocked.
For example, if Sam has blocked 8/21/2021 and 9/11/2021, he should not be selected if the corresponding dates are selected from the Games table. Sam should show up if 9/18/2021 is selected, however. I have 3 tables:
Officials tbl
RefId Name
---------------------
1 Jack
2 Sam
3 Jane
Games tbl Blocks tbl
GameId GameDate BlockId RefId BlockDate
------------------------- ----------------------
1 8/21/2021 1 2 8/21/2021
2 9/11/2021 2 2 9/11/2021
3 9/18/2021 3 3 8/21/2021
Desired Output
----------------------------------
If Game 1 is selected: Jack
If Game 2 is selected: Jack and Jane
If Game 3 is selected: Jack, Sam and Jane
The only 2 tables that are related are the Officials table and Blocks table, with the RefId. I need to compare the BlockDate of Blocks table to GameDate of Games table. I have tried some sql language and this below is obviously not correct, but I'm looking for a way to accomplish what I want to do:
#GameDate datetime,
Select c.Id, c.Name
From Officials c
Where In c.Id And Blocks.BlockDate <> Games.GameDate)
You can do it with NOT EXISTS:
SELECT o.*
FROM Officials o
WHERE NOT EXISTS (
SELECT 1
FROM Blocks b INNER JOIN Games g
ON g.GameDate = b.BlockDate
WHERE b.RefId = o.RefId AND g.GameId = ?
);
See the demo.

Complex SQL Query in JOIN

Tables
TRANSACTIONS
SUPP_ID | PAYMENT
----------+----------
1001 200
1002 100
1005 250
MASTER_SUPPLIERS
SUPP_ID | AREA
----------+----------
1001 ABC
1002 XYZ
1003 TYU
1004 MNO
1005 PQR
Intention:
Find those count of suppliers area wise where no payment (NO_TRANS_CNT) has been received
SELECT AREA, COUNT(*) AS NO_TRANS_CNT FROM MASTER_SUPPLIERS
WHERE AREA NOT IN (SELECT DISTINCT(AREA) FROM TRANSACTIONS)
GROUP BY AREA
AREA | NO_TRANS_CNT
----------+--------------
TYU 1
MNO 1
Want to ask: Now, I also want to add the column TOTAL_SUPPLIERS in this area
AREA | TOTAL SUPPLIERS | NO_TRANS_CNT
----------+--------------------+----------------
ABC 1 0
XYZ 1 0
TYU 1 1
MNO 1 1
PQR 1 0
I think it can be achieved using JOINs, but I am not able to get how ?
Try this:
SELECT
M.AREA
, COUNT(1) TOTAL_SUPPLIERS
, COUNT(CASE WHEN T.SUPP_ID IS NULL THEN 1 END) NO_TRANS_CNT
FROM MASTER_SUPPLIERS M
LEFT JOIN TRANSACTIONS T ON T.SUPP_ID = M.SUPP_ID
GROUP BY M.AREA;
Something like
select M.AREA, COUNT(*) as TOTAL_SUPPLIERS, COUNT(T.PAYMENT) as NO_TRANS_CNT
from MASTER_SUPPLIERS M left join TRANSACTIONS T
on M.SUPP_ID = T.SUPP_ID
group by M.AREA;
could work.
Note that the COUNT(T.PAYMENT) only counts those where the PAYMENT is not NULL.
Use a left join, but start with suppliers:
select ms.area, count(*) as num_suppliers, count(t.supp_id) as num_transactions
from master_suppliers ms left join
transactions t
on t.supp_id = m.supp_id
group by ms.area;
The left join keeps everything in the first table -- which is what you want, along with matching rows from the second.
When you count the number of transactions, the argument to count() should either be a column used in the on clause or the primary key.

Count of column from joined table but include zeroes (can't get LEFT JOIN to work)

I have to tables. One with Users (called Actor) and one with Orders (called Ord).
Each order can be assigned to one user, but not all orders have users assigned.
I want to make a select statement that returns all my users and show how many orders are assigned to each one. Including those users that have no orders assigned.
Pretty simple, but for some reason I can't get it to work.
This is what I've got so far:
SELECT Usr, COUNT(Ord.OrdNo)
FROM Actor
LEFT JOIN Ord on Actor.EmpNo = Ord.Rsp
WHERE Actor.Gr2 <> 9
AND Actor.R1 = 10
AND Ord.OrdTp = 6
AND Ord.OrdPrSt2 != 0x10
GROUP BY Actor.Usr
This just returns the users that have orders assigned to them, but I want all users returned, just with a zero if they have no orders assigned.
Please disregard the WHERE clauses (I havent't included the columns/values in the sample data below). Despite these I should still get around 10 users returned when running the query on my live data.
Sample data
Table: Actor
Usr EmpNo
----------------
ben 123
jane 124
jack 125
tom 126
Table: Orders
OrdNo Rsp
----------------
555551 123
555552 123
555553 124
555554 126
This is what I want returned:
Usr Count
----------------
123 2
124 1
125 0
126 1
But instead I get this:
Usr Count
----------------
123 2
124 1
126 1
So what am I missing?
Move the Ord conditions from WHERE to ON to get true LEFT JOIN result:
SELECT Usr, COUNT(Ord.OrdNo)
FROM Actor
LEFT JOIN Ord on Actor.EmpNo = Ord.Rsp
AND Ord.OrdTp = 6
AND Ord.OrdPrSt2 != 0x10
WHERE Actor.Gr2 <> 9
AND Actor.R1 = 10
GROUP BY Actor.Usr
without the where condition i am getting the desired results. here is the code i ran:
select a.empno,
count(ordrno)
from actor a left join orders b
on a.empno = b.rsp
group by a.empno

i want to get the values from two tables

i got two tables
office accnt id
------------------------------
HR poop 1
HR fart 2
EXEC poop 3
and
id number
-----------------------
1 2
1 2
1 1
2 5
2 1
3 6
and what i wanted to be the output is like this
id office accnt number
--------------------------------------------
1 HR poop 5
2 HR fart 6
3 EXEC poop 6
and here's what I've tried so far
SELECT AccntTbl.office, AccntTbl.accnt, SUM(NumberTbl.Number)
FROM AccntTbl INNER JOIN
NumberTbl ON AccntTbl.Id = NumberTbl.Id
and sadly i can't get what i want..glad for any help.. :)
select a.id, a.office, a.accnt, SUM(n.Number)
from AccntTbl a INNER JOIN
NumberTbl n ON a.AccntTbl.Id = NumberTbl.Id
SELECT Accnt.id,Accnt.office, Accnt.accnt, SUM(Num.Number)
FROM AccntTbl Accnt INNER JOIN
NumberTbl Num ON Accnt.Id = Num.Id
It just needs a GROUP BY with the id, the office and the accnt.
SELECT
acc.id, acc.office, acc.accnt,
SUM(num.Number) AS number
FROM AccntTbl acc
JOIN NumberTbl num
ON acc.Id = num.Id
GROUP BY
acc.id, acc.office, acc.accnt

SQL Query with two tables

I have two tables as following
Point: ListMember:
index description indexParent indexChild
-------------------- ---------------------------
1 ABC 333 1
2 DEF 333 2
3 GHI 444 1
333 Hello 444 2
444 Bye 444 3
555 Welcome
An example of result table that i am looking for
Result:
Index description listSize descriptionChild
333 Hello 2 ABC
333 Hello 2 DEF
444 Bye 3 ABC
444 Bye 3 DEF
444 Bye 3 GHI
555 Welcome 0
I am new to database and still learning SQL so i am not quite sure how to do the select to obtain the result i am looking for.
Assuming your results should be 333 Hello. You have to do two left joins (for 555 with no children).
psuedo code:
Select p.index, p.description, p2.index as listsize, p2.description as descriptionchild
from point p
left join listmember l
on p.index = l.indexparent
left join point p2
on l.indexchild = p2.index
Due to using the unfortunate column name index, you have to include brackets every time you refer to that column. This is working for me:
SELECT P.[index] AS [Index],
P.description,
(SELECT COUNT(*) FROM ListMember WHERE indexParent = P.[index]) AS listSize,
P2.description AS descriptionChild
FROM Point P
LEFT JOIN ListMember LM ON LM.indexParent = P.[index]
LEFT JOIN Point P2 ON P2.[index] = LM.indexChild
WHERE P.[index] NOT IN (SELECT indexChild FROM ListMember)
ORDER BY P.[index]
I do believe the following query should work for you (SQL Fiddle):
SELECT p1.[index], p1.description,
(
SELECT COUNT(1)
FROM ListMember ls
WHERE ls.indexParent = p1.[index]
) AS listSize,
p2.description AS descriptionChild
FROM Point p1
LEFT JOIN ListMember l ON l.indexParent = p1.[index]
LEFT JOIN Point p2 ON l.indexChild = p2.[index]
WHERE p1.[index] NOT IN
(
SELECT indexChild FROM ListMember
)