SQL Server : how to union 3 tables with different number of rows - sql-server

I have 3 tables with different data and I need to return one table that includes all 3 tables:
Customer
Contacts
Addresses
I want to get the data in only one table and one record with all details like CustomerNumber, Name, City, officeNumber...., like Union
SELECT CU.[Name]
FROM Customers CU
WHERE CustomerNumber = #CustomerId
AND IsDeleted = 0
SELECT AD.City, AD.Street
FROM [Addresses] AD
WHERE CustomerId = #CustomerId
AND IsDeleted = 0
SELECT CO.FullName, CO.OfficeNumber, CO.Email
FROM [Contacts] CO
WHERE CustomerId = #CustomerId
AND IsDeleted = 0
Result:

Number of rows doesn't matter for a union number of columns do.
What do you expect with a union?
I suppose you want you want all information (name address, contact) of customer having Id= #CustomerId
If I am right, you should make 2 join between the 3 tables using CustomerId as join clause
Edit:
https://www.db-fiddle.com/f/uGhtAZAVk64KzgThGekKk6/11

You need to JOIN the tables not UNION them. Please research SQL Server JOIN as there multiple types of joins you can do. In this case you're looking for an INNER JOIN this type of join will only return records when you have matching keys in all the tables. The key in your case is the customer id. You JOIN the tables ON customer id. Your query should look something like this:
SELECT CU.[Name], AD.City, AD.Street, CO.FullName, CO.OfficeNumber, CO.Email
FROM Customers CU
INNER JOIN [Addresses] AD
ON CU.CustomerNumber = AD.CustomerId
INNER JOIN [Contacts] CO
ON CO.CustomerId = CU.CustomerNumber
WHERE CU.CustomerNumber = #CustomerId

Related

Deconstructing a complex SQL query into multiple queries and joins

Could someone please help break up this complex SQL query into individual steps? I am trying to build multiple tables and joins out of this multistep query that feels quite opaque. Thank you!
select
visit_date,
count(vo1.visit_id) as num_visits,
sum(case when co1.person_id is not null then 1 else 0 end) as num_visits_w_cond
from
visit_occurrence vo1
left join
(select distinct
person_id, visit_id, condition_date
from
condition_occurrence
where
condition_id = 12345)) co1 on vo1.person_id = co1.person_id
and vo1.visit_date = co1.condition_date
and vo1.visit_id = co1.visit_id
where
visit_id = 1234
group by
visit_date
order by
visit_date;
Ideally, I'd like to generate a few data tables in the intermediate steps and then join and count at the end but am not sure what this would look like.
EDIT: Thank you for your comments. Regarding clarity of the individual tables:
The first select will query the visit_occurrence table for all visit_ids that match a visit_id # of "1234" and return the distinct person_id, visit_date, and visit_id for all visits. So a person_id, visit_date, visit_id tuple is unique, i.e. the same person_id with a different visit_date or different visit_id does not qualify as a duplicate. Only an identical tuple is a duplicate.
The second select will query the condition_occurrence table for all condition_ids that match a condition_id # of 12345 and return distinct person_id, visit_id, condition_date. So a person_id, visit_id, condition_date tuple is unique, i.e. the same person_id with a different visit_id or condition_date is not a duplicate. Only an identical tuple is a duplicate.
Join table 1 and table 2 on person_id, visit_date = condition_date, visit_id = visit_id. Then count how many distinct person_ids occur on each date.
From table 1, count how many visit_ids are associated with each date.
Hopefully that's more clear? Thank you again for the feedback.
I doubt this will perform any better, but it's close to what you're asking for. I would stay away from temp tables (which is what I inferred from your question).
with cteVO as --common table expression for visit_occurrence
(
select distinct person_id, visit_date, visit_id
from visit_occurrence
where visit_id = 1234
),
cteCO as -- common table expression for condition_occurrence
(
select distinct person_id, visit_id, condition_date
from condition_occurrence
where condition_id = 12345
)
-- Join both CTEs to get the count of person_id and count of visit_id
SELECT cteVO.visit_date, COUNT(cteVO.person_id) AS count_person_id,
COUNT(cteVO.visit_id) AS count_visit_id
FROM cteVO
INNER JOIN cteCO ON cteVO.person_id = cteCO.person_id
AND cteVO.visit_date = cteCO.condition_date
AND cteVO.visit_id = cteCO.visit_id
GROUP BY cteVO.visit_date

Retrieving borrower name based on borrowertype id from another table in SQL Server

I have two tables, Customer and RegisteredCustomer.
Customer table has the first and last name of customers including the family members stored against each Residentid.
The RegisteredCustomer has the CustomerType as 1 being primary and 2 being FamilyMembers.
I want to select both the primary and Familymember displayed side by side.
Select FirstName, LastName
from Customer
Inner Join RegisteredCustomers on Customer.Customerid = RegisteredCustomer.Customerid
and CustomerType = 1
How can I achieve it?
Thanks
Try it like this:
Select a.Customerid,FirstName, LastName,b.CustomerType from
(Select Customerid,FirstName, LastName from Customer) as a
left join
(select Customerid,cusdescription,CustomerType from RegisteredCustomers)as b
on a.Customerid = b.Customerid where CustomerType = 1
Hope it could help.

SQL Server : return value in specific table2 column based on value in table1

I have a query that gets data from 2 tables.
Transaction table contains week_id, customer_id, upc12, sales_dollars
Products table contains upc12, column_1, column_2, column_3
I want my query to return the value in products table, based on what the customer_id is in the transaction table. customer_id = 1 should return column_1, customer_id = 2 should return column_3, etc.
SELECT
t.week_id,
customer_id,
upc12,
p.___________ sum(t.sales_dollars)
FROM
transaction t, products p
WHERE
t.upc_12 = p.upc_12
GROUP BY
t.week_id, customer_id, upc12, p.___________
Sorry if this makes no sense, but my research hasn't been very good, as I don't know how to correctly formulate my question. You probably guessed I'm new to SQL.
Thanks!
Here is one way to do it:
;WITH cte as
(
SELECT
t.week_id,
customer_id,
upc12,
CASE customer_id
WHEN 1 THEN p.Column_1
WHEN 2 THEN p.Column_2
WHEN 3 THEN p.Column_3
END As ColByCustomer,
t.sales_dollars
FROM transaction t
INNER JOIN products p on t.upc_12 = p.upc_12
)
SELECT week_id, customer_id, upc12, ColByCustomer, SUM(sales_dollars)
FROM cte
GROUP BY week_id, customer_id, upc12, ColByCustomer

SELECT from multiple queries

I have this tables:
tblDiving(
diving_number int primary key
diving_club int
date_of_diving date)
tblDivingClub(
number int primary key not null check (number>0),
name char(30),
country char(30))
tblWorks_for(
diver_number int
club_number int
end_working_date date)
tblCountry(
name char(30) not null primary key)
I need to write a query to return a name of a country and the number of "Super club" in it.
a Super club is a club which have more than 25 working divers (tblWorks_for.end_working_date is null) or had more than 100 diving's in it(tblDiving) in the last year.
after I get the country and number of super club, I need to show only the country's that contains more than 2 super club.
I wrote this 2 queries:
select tblDivingClub.name,count(distinct tblWorks_for.diver_number) as number_of_guids
from tblWorks_for
inner join tblDivingClub on tblDivingClub.number = tblWorks_for.club_number,tblDiving
where tblWorks_for.end_working_date is null
group by tblDivingClub.name
select tblDivingClub.name, count(distinct tblDiving.diving_number) as number_of_divings
from tblDivingClub
inner join tblDiving on tblDivingClub.number = tblDiving.diving_club
WHERE tblDiving.date_of_diving <= DATEADD(year,-1, GETDATE())
group by tblDivingClub.name
But I don't know how do I continue.
Every query works separately, but how do I combine them and select from them?
It's university assignment and I'm not allowed to use views or temporary tables.
It's my first program so I'm not really sure what I'm doing:)
WITH CTE AS (
select tblDivingClub.name,count(distinct tblWorks_for.diver_number) as diving_number
from tblWorks_for
inner join tblDivingClub on tblDivingClub.number = tblWorks_for.club_number,tblDiving
where tblWorks_for.end_working_date is null
group by tblDivingClub.name
UNION ALL
select tblDivingClub.name, count(distinct tblDiving.diving_number) as diving_number
from tblDivingClub
inner join tblDiving on tblDivingClub.number = tblDiving.diving_club
WHERE tblDiving.date_of_diving <= DATEADD(year,-1, GETDATE())
group by tblDivingClub.name
)
SELECT * FROM CTE
You can combine the queries using a UNION ALL as long as there are the same number of columns in each query. You can then roll them into a Common Table Expression (CTE) and do a select from that.

How can I get this query to return 0 instead of null?

I have this query:
SELECT (SUM(tblTransaction.AmountPaid) - SUM(tblTransaction.AmountCharged)) AS TenantBalance, tblTransaction.TenantID
FROM tblTransaction
GROUP BY tblTransaction.TenantID
But there's a problem with it; there are other TenantID's that don't have transactions and I want to get those too.
For example, the transaction table has 3 rows for bob, 2 row for john and none for jane. I want it to return the sum for bob and john AND return 0 for jane. (or possibly null if there's no other way)
How can I do this?
Tables are like this:
Tenants
ID
Other Data
Transactions
ID
TenantID (fk to Tenants)
Other Data
(You didn't state your sql engine, so I'm going to link to the MySQL documentation).
This is pretty much exactly what the COALESCE() function is meant for. You can feed it a list, and it'll return the first non-null value in the list. You would use this in your query as follows:
SELECT COALESCE((SUM(tr.AmountPaid) - SUM(tr.AmountCharged)), 0) AS TenantBalance, te.ID
FROM tblTenant AS te
LEFT JOIN tblTransaction AS tr ON (tr.TenantID = te.ID)
GROUP BY te.ID;
That way, if the SUM() result would be NULL, it's replaced with zero.
Edited: I rewrote the query using a LEFT JOIN as well as the COALESCE(), I think this is the key of what you were missing originally. If you only select from the Transactions table, there is no way to get information about things not in the table. However, by using a left join from the Tenants table, you should get a row for every existing tenant.
Below is a full walkthrough of the problem. The function isnull has also been included to ensure that a balance of zero (rather than null) is returned for Tenants with no transactions.
create table tblTenant
(
ID int identity(1,1) primary key not null,
Name varchar(100)
);
create table tblTransaction
(
ID int identity(1,1) primary key not null,
tblTenantID int,
AmountPaid money,
AmountCharged money
);
insert into tblTenant(Name)
select 'bob' union all select 'Jane' union all select 'john';
insert into tblTransaction(tblTenantID,AmountPaid, AmountCharged)
select 1,5.00,10.00
union all
select 1,10.00,10.00
union all
select 1,10.00,10.00
union all
select 2,10.00,15.00
union all
select 2,15.00,15.00
select * from tblTenant
select * from tblTransaction
SELECT
tenant.ID,
tenant.Name,
isnull(SUM(Trans.AmountPaid) - SUM(Trans.AmountCharged),0) AS Balance
FROM tblTenant tenant
LEFT JOIN tblTransaction Trans ON
tenant.ID = Trans.tblTenantID
GROUP BY tenant.ID, tenant.Name;
drop table tblTenant;
drop table tblTransaction;
Select Tenants.ID, ISNULL((SUM(tblTransaction.AmountPaid) - SUM(tblTransaction.AmountCharged)), 0) AS TenantBalance
From Tenants
Left Outer Join Transactions Tenants.ID = Transactions.TenantID
Group By Tenents.ID
I didn't syntax check it but it is close enough.
SELECT (SUM(ISNULL(tblTransaction.AmountPaid, 0))
- SUM(ISNULL(tblTransaction.AmountCharged, 0))) AS TenantBalance
, tblTransaction.TenantID
FROM tblTransaction
GROUP BY tblTransaction.TenantID
I only added this because if you're intention is to take into account for one of the parts being null you'll need to do the ISNULL separately
Actually, I found an answer:
SELECT tenant.ID, ISNULL(SUM(trans.AmountPaid) - SUM(trans.AmountCharged),0) AS Balance FROM tblTenant tenant
LEFT JOIN tblTransaction trans
ON tenant.ID = trans.TenantID
GROUP BY tenant.ID

Resources