merging two tables and adding additional column - sql

I am using sql-server. I have two tables (simple snap shot below).
table hlds table bench
name country wgt name country wgt
abc us 30 abc us 40
mno uk 50 ppp fr 45
xyz us 20 xyz us 15
what I would like to do is calculate the differnces in the wgt columns and insert the results into another table, lets call it merge_tbl. The other thing I would like to do is in merge_tbl have a bit column where it is 1 if the company exists in the table hlds.
So I would like the result to look like below,
merge_tbl
name country wgt inHld
abc us -10 1
mno uk 50 1
xzy us 5 1
ppp fr -45 0
How do I go about doing this?

I think you need a FULL OUTER JOIN to get records from both tables. Then, you can use a INSERT INTO SELECT statement to do the insert:
INSERT INTO merge_tbl
SELECT COALESCE(h.name, b.name) AS name,
COALESCE(h.country, b.country) AS country,
COALESCE(h.wgt, 0) - COALESCE(b.wgt, 0) AS wgt,
CASE WHEN h.name IS NOT NULL THEN 1
ELSE 0
END AS inHld
FROM hlds AS h
FULL OUTER JOIN bench AS b ON h.name = b.name AND h.country = b.country
The ON clause of the JOIN operation depends on your actual requirements. I have made the assumption that records from hlds, bench tables match if both name and country fields are equal.
Demo here

Related

SQL from a column of a query to row of another query

I am looking for a method that extracts the dates of Result 2, add
to be columns of Result 1, final as Expect result.
After Googled, I tried to use transform but mess result. How could
I build the result? Thanks.
Result 1:
merchantRef
totalAmount
country
1
10
UK
2
20
UK
3
60
UK
SELECT tblThree.merchantRef, tblThree.inDate
FROM tblThree;
Result 2 (tblThree):
merchantRef
inDate
1
12/21/2010
2
02/28/2021
3
06/15/2021
3
07/15/2021
Expect result:
merchantRef
totalAmount
country
inDate
inDate2
1
10
UK
12/21/2010
2
20
UK
02/28/2021
3
60
UK
06/15/2021
07/15/2021
You can use a lateral join -- which is like a subquery that can return multiple rows:
select t1.*, t3.*
from table1 t1 outer apply
(select nullif(min(t3.indate), max(t3.indate)) as indate1,
nullif(max(t3.indate), min(t3.indate)) as indate2
from table3 t3
where t3.merchantRef = t1.merchantRef
) t3;

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

Sybase SQL select statement to collapse and condense rows by an ID

I need help constructing an SQL statement with Sybase to collapse rows linked by three columns, ID, Name and DEPT. I have one table TABLE1:
ID NAME DEPT CAT
1 ghi P
1 CV G
2 abc P
2 IT G
2 HC G
3 def P
3 jkl P
3 ENT G
3 MC G
The CAT column means category. The P column means person. The G column means group.
ID can be person(NAME) as well as group(DEPT).
If ID(1) is associated with a person(NAME) as well as a group(DEPT) then I want to update the person(NAME) row to have DEPT name as well and then delete the group(DEPT) row. If ID(2) is associated with one person(NAME) and more than one DEPT(group) then I want to have two rows for that NAME. If ID(3) contains two different NAME and two different DEPT then I want separate rows for each NAME and DEPT as shown below:
Below is the expected output I want:
ID NAME DEPT CAT
1 ghi CV P
2 abc IT P
2 abc HC P
3 def ENT P
3 def MC P
3 jkl ENT P
3 jkl MC P
I would like an SQL statement that returns the above rows from TABLE1. Is it possible?
This might work for you.
SELECT t1.ID, t1.NAME, t2.DEPT, t1.CAT
FROM TABLE1 AS t1
INNER JOIN TABLE1 AS t2 ON (t1.ID = t2.ID)
WHERE t2.DEPT IS NOT NULL AND t1.NAME IS NOT NULL

SQL Select Master Records and Display Number of Detail Records for Each

I have a Master and Detail table, the Detail linking to the Master record on a FK reference.
I need to display all the data from the Master table, and the corresponding number of details for each record, i.e.
MASTER TABLE
ID Name Age
1 John 15
2 Jane 14
3 Joe 15
DETAIL
MasterID Subjects
1 Trigonometry
1 Chemistry
1 Physics
1 History
2 Trigonometry
2 Physics
Thus, when I ran the SQL statement, I would have the following result:
ID Name Age #Subjects
1 John 15 4
2 Jane 14 2
3 Joe 15 0
Thanks!
This may be useful
SELECT mt.ID, mt.NAME, mt.AGE, COUNT(d.MasterID) as [#Subjects]
FROM MasterTable mt
LEFT OUTER JOIN Detail d on mt.ID = d.ID
GROUP BY mt.ID, mt.NAME, mt.AGE
ORDER BY mt.ID
select id,
name,
age,
( select count(*)
from detail
where master.id = detail.id ) as record_count
from master
syntax adjusted depending on what db you are using