Access SQL: Union select, show both fields - sql

I have this SQL:
SELECT Ph.Account, Ph.Ct FROM Ph
UNION SELECT Rx.Account, Rx.Ct FROM Rx;
Which works fine, but the Ph.Ct and Rx.Ct fields may not always be the same. So I wanted to display both of them, but the query is only showing 1 "Ct" field and not both.
How can I have it show both?
Here's ph:
12685 3
29568 1
38771 2
Here's rx:
10657 1
12685 2
68781 2
79874 1
What's what I want to come out from the query:
Account ph.ct rx.ct
10657 1
12685 3 2
29568 1
38771 2
68781 2
79874 1
A UNION gets the correct data set (about 800 results), but not the right fields. Any JOINs I've tried do not give the right data set (only about 300 results).

What you need is a full outer join. For each value of Account appearing in either table, this will give the corresponding values of Ct for each table if the given value of Account appears and null otherwise.
select Account,Ph.Ct as ph_ct,Rx.Ct as rx_ct
from Ph full outer join Rx on (Ph.Account=Rx.Account);
Edit: Since Access apparently doesn't support full outer joins (for some god awful reason), you can achieve the same effect with the union of a left join with a right join:
select Ph.Account, Ph.Ct as ph_ct, Rx.Ct as rx_ct
from Ph left join Rx on (Ph.Account=Rx.Account)
union
select Rx.Account, Ph.Ct as ph_ct,Rx. Ct as rx_ct
from Ph right join Rx on (Ph.Account=Rx.Account);
which is also equivalent to (the probably faster):
select Ph.Account, Ph.Ct as ph_ct, Rx.Ct as rx_ct
from Ph left join Rx on (Ph.Account=Rx.Account)
where (Rx.Account IS NULL)
union all
select Rx.Account, Ph.Ct as ph_ct, Rx.Ct as rx_ct
from Ph right join Rx on (Ph.Account=Rx.Account);

You cannot have a full outer join in MS Access, so:
SELECT m.Account, Ph.Ct, Rx.Ct FROM
((SELECT Ph.Account FROM Ph
UNION SELECT Rx.Account FROM Rx) As m
LEFT JOIN Ph ON m.Account = Ph.Account)
LEFT JOIN Rx ON m.Account = Rx.Account

I don't think you want a union. You want a join. If you join the fields on Account, you can show the Rx.Ct and Ph.Ct as well.
In a union, it lists all the rows from one table, stacked on top of another table, excluding duplicates. Each row is from a different table.
In a join, each row is a combination of two tables, which means the columns that are not joined can hold different values.
Here you go:
SELECT Ph.Account, Ph.Ct, Rx.Ct FROM Ph INNER JOIN Rx ON Ph.Account=Rx.Account;

Just for future references about UNION Operator:
The UNION operator is used to combine the result-set of two or more SELECT statements.
Notice that each SELECT statement within the UNION must have the same number of columns. The columns must also have similar data types. Also, the columns in each SELECT statement must be in the same order.
Note: The UNION operator selects only distinct values by default. To allow duplicate values, use UNION ALL.
For more info: UNION Operator

You want a join, not a union:
select
coalesce(Ph.Account, Rx.Account) as Account
Ph.Ct,
Rx.Ct
from
Ph
full outer join Rx on
Ph.Account = Rx.Account
You can change inner to the type of join you want. Read more about the different types of joins here.
unions are used when you want to take one set of results and append them to the rowset of another result. joins are used when you want to take one set of results and append them to the columnset of another result.

Related

Need help in joining tables to get the accurate results

I have 4 tables, the 1st table 'LD0P0K' is the main table i need to join with 2nd 'LD0P0K01' and 3rd 'LD0P0K04' with the 1st column value 'HUSHLNR' and get the 'PNR' from both tables and then join with last table 'LD0P0A' to get the values with 'PNR'.
I tried the below solution but its not giving the data from 3rd table and giving 6 records with 2 rows for each 2nd table.
Select HS.HUSHLNR, HS.FOMDAT,HS.TOMDAT,HSM.PNR,HSM.FAMHUVUD,HSM.MARK,HSM.AVFOMDAT,HSM.AVTOMDAT,P.KUNDNUMMER,P.FODDAT from LD0P0K HS
LEFT OUTER JOIN LD0P0K01 HSM on HS.HUSHLNR = HSM.HUSHLNR
LEFT OUTER JOIN LD0P0K04 CHM on HS.HUSHLNR = CHM.HUSHLNR
LEFT OUTER JOIN LD0P0A P on p.PNR= HSM.PNR AND p.PNR = CHM.PNR
Where HS.HUSHLNR='906'
You can simply use Union to combined the fields
Here is the link for Union to understand
SQL Union
and here is the code change it whatever you want
Select HS.HUSHLNR as HUSHLNR, HS.fromdate as FromDte,HSM.PNR as PNR from LD0P0K HS
inner JOIN LD0P0K01 HSM on HS.HUSHLNR = HSM.HUSHLNR
union
Select CHM.HUSHLNR as HUSHLNR, '' as FromDte,CHM.PNR as PNR from LD0P0K04 CHM
order by PNR
Output:

Minus operation gives wrong answer

I am trying to get the result of the minus operation of join tables which means that I am finding unmatched records.
I tried:
SELECT count(*) FROM mp_v1 mp
left join cm_v1 sop
on mp.study_name=sop.study_name and
sop.site_id=sop.site_id
--where mp.study_name='1101'
MINUS
SELECT count(*) FROM iv_mpv1 mp
inner join cm sop
on mp.study_name=sop.study_name and
sop.site_id=sop.site_id
--where mp.study_name='1101'
output: the count of this gives me 171183251
but when I run the first query individually I get 171183251 for left outer join and 171070345 for inner join so the output needs to be 112906. I am not sure where my query is wrong. Could anyone please give your opinion.
If you want unmatched records you wouldn't use MINUS on the counts. The query would look more like:
SELECT COUNT(*)
FROM ((SELECT *
FROM mp_v1 mp LEFT JOIN
cm_v1 sop
USING (study_name, site_id)
) MINUS
(SELECT *
FROM iv_mpv1 mp LEFT JOIN
iv_cmv1 sop
USING (study_name, site_id)
)
) x;
Also note that MINUS removes duplicates, so if you have duplicates within each set of tables, then they only count as one row.
The SELECT * assumes that the tables have the same columns and compatible types -- which makes sense given the gist of the question. You may need to list the particular columns you care about.

SQL query returning more than one result

This is my SQL query
SELECT
room.*, reservation.rn, reservation.cin
FROM
room, reservation
But it is returning 4 instances of each row.
I just want to get the corresponding reservation from another table where they have same room number and at the same time display the remaining rooms
Room Table
Id,r_num,r_price,in_date,out_date
reservation_table
id,r_num,cIn,cOut
You have a cross join between the two tables as there is no join condition.
Assuming the reservation table has room_id FK which references id from room table, you can join like this:
select r.*,
s.rn,
s.cin
from room r
join reservation s on r.id = s.room_id
Always use proper explicit join syntax instead of comma based joins.
Your select statement results in a cross join / cartesian product.
Use a WHERE-clause!
SELECT room.*,reservation.rn,reservation.cin FROM room,reservation WHERE room.room_no = reservation.room_no
For more complicated joins I recommend using an explicit syntax with the appropriate keywords, although your implicit join is perfectly fine for this case (and performance wise implicit and explicit joins are the same).
To display unreserved rooms as well (so to keep results that do not satisfy the where-clause) you'll have to use an OUTER JOIN (LEFT or RIGHT depending on what you want to keep) like this:
SELECT room.*,reservation.rn,reservation.cin
FROM room LEFT OUTER JOIN reservation
ON room.room_no = reservation.room_no
For the first part you need a join and for second condition you need union :
select r.Id,r.r_num,r.r_price,r.in_date,r.out_date,s.id as resId,s.r_num,s.cIn,s.cOut
from room r
join reservation s on r. r_num = s. r_num
union
select r.Id,r.r_num,r.r_price,r.in_date,r.out_date,null as resId, null as r_num, null as cIn,null as cOut
from room r
where r.in_date is null
union by default distinct the result if you need repeated rows just use UNION ALL

JOIN Tables with all specified fields matching

I have two tables. I'm selecting all the values in the first table and trying to get the associated rows in the second table which match BOTH of the specified fields.
So in this example, I want only the rows in the CarsTable and the associated columns in the TrucksTable in which BOTH the Tires and Windows values match (if just one value matches, I don't want it). I'm not even certain a join is the correct operation. Any ideas?
SELECT * FROM CarsTable, TrucksTable
LEFT JOIN TrucksTable t1
ON
t1.Tires = Cars.Tires
LEFT JOIN Trucks t2
ON
t2.Windows = Cars.Windows
You need to do some research on joins...your from clause is all over the place. Carstable,truckstable as you have here is a cross join..and I don't understand what the left joins you are doing are. I think you only have two tables:
SELECT c.*, t.* FROM CarsTable c
inner join TrucksTable t
on t.tires = c.tires and t.windows = c.windows
inner join will function as a filter...if the record in carstable finds no matches in the truckstable by the keys listed, it won't appear. If you want all cartable rows even those that find no match, use left join (in this case, t.* will be null)

Getting all records including non matching records

I have the following tables
Payment
PayTypeId, Description
0 , Credit
1, Debit
2,Master
ActualPayment
Id,PayTypeId,Amount
1,1,10
Here is the output i am looking at
Id,PayTypeId,Amount
1,0,NULL
1,1,10
1,2,NULL
Basically I want all the records of ActualPayment including all payment types.
Here is the query i have used but am not getting any records
select
*
from #ActualPayments ap
left join #Payment p on ap.paytypeid = p.paytypeid
where p.paytypeid is null
If you want one record for each of the three PayTypeID values, then you need those three records on the left-hand side of the LEFT JOIN.
Equally, if you want the ActuallPaymentID on each output line, that value needs to be on the left hand side.
It's all leading you down the wrong avenue with the data that you have, and the tables that you have described.
With just those two tables in your question, I would use this layout instead...
SELECT
ap.ActualPaymentID,
p.PayTypeID,
SUM(CASE WHEN ap.PayTypeID = p.PayTypeID THEN ap.Amount END) AS Amount
FROM
ActualPayments AS ap
CROSS JOIN
Payment AS p
GROUP BY
ap.ActualPaymentID,
p.PayTypeID
You aren't receiving any records because you are filtering everything out with the WHERE clause p.paytypeid is null
Try running it without the WHERE clause.
Edit: The below SQL should return the correct information. I've used a CROSS JOIN to create an in-line view. This should remove the unwanted NULLs.
SELECT t1.id, t1.paytypeid, t2.amount
FROM (
SELECT id, payment.paytypeid
FROM #ActualPayments
CROSS JOIN #Payment
) t1
LEFT OUTER JOIN #ActualPayments t2
ON t1.paytypeid = t2.paytypeid
;
I think you want a FULL OUTER JOIN:
select
*
from #ActualPayments ap
full outer join #Payment p
on ap.paytypeid = p.paytypeid
;
This will return all rows from the ActualPayments table along with their corresponding values from Payment - if there is any. Additional it will return all rows from Payment for which no ActualPayments exist.
Please note: The where clause of your sample query must not be used!
I'm confused why you would want to do this, but here's one way
select ap.Id, pt.PayTypeId, ap2.Amount
from #ActualPayments ap
cross join #PaymentTypes pt
left join #ActualPayments ap2
on pt.PayTypeId = ap2.PayTypeId
and ap.Id = ap2.id