Performing select count across two tables sql - sql

I have a table relationship which links one person to many relatives. so the tables are 1. Client. 2. Client_relative. I want to display all the rows of the Persons table, while displaying a count of how many relatives each person has. I have this query:
SELECT c.clientid, c.fname, c.lname, count(cr.relativeid) as relativecount FROM {client} AS c INNER JOIN {client_relative} cr on c.clientid = cr.clientid
This isn't working. Any ideas?

select c.*, cc.relativecount
from client c
inner join (
select clientid, count(*) as relativecount
from client_relative
group by clientid
) cc on c.clientid = cc.clientid

Related

Filter results through two values in the same column if one is multiple

I am trying to list customers who have purchased from ProductCategoryKey 1, and if those customers have purchased ProductCategoryKEY 3 more than once show only one row for that customer. My code so far only filters through PC Key 1. How can I say 'of those who have purchased PC Key 1, how many have purchased PC Key 3 at least two times and only show that person once?'
SELECT DISTINCT C.FirstName, C.LastName, PC.EnglishProductCategoryName
FROM dbo.FactInternetSales AS I
INNER JOIN dbo.DimCustomer AS C
ON I.CustomerKey = C.CustomerKey
INNER JOIN dbo.DimProduct AS P
ON I.ProductKey = P.ProductKey
INNER JOIN dbo.DimProductSubcategory AS SC
ON P.ProductSubcategoryKey = SC.ProductSubcategoryKey
INNER JOIN dbo.DimProductCategory as PC
ON SC.ProductCategoryKey = PC.ProductCategoryKey
WHERE PC.ProductCategoryKey = 1
ORDER BY C.LastName ASC, FirstName ASC;
Using Microsoft SQL Server 2019
ADventureWorksDW2017
I'm a big fan of using temp tables, or variable tables, as a way to further filter data. The first query gets all customers with a PC Key of 1 and 3, and inserts those records into a temp table. Then, the second query uses aggregation and a GROUP BY clause to count all rows where the PC Key is 3, followed by a HAVING clause where the count is > 2. The GROUP BY clause in the second query effectively creates a distinct record-set for your last requirement.
I break up the query into two queries for readability. You could also use nested sub queries to achieve the same result.
SELECT DISTINCT C.FirstName, C.LastName, PC.EnglishProductCategoryName,
PC.ProductCategoryKey
into #temp1
FROM dbo.FactInternetSales AS I
INNER JOIN dbo.DimCustomer AS C
ON I.CustomerKey = C.CustomerKey
INNER JOIN dbo.DimProduct AS P
ON I.ProductKey = P.ProductKey
INNER JOIN dbo.DimProductSubcategory AS SC
ON P.ProductSubcategoryKey = SC.ProductSubcategoryKey
INNER JOIN dbo.DimProductCategory as PC
ON SC.ProductCategoryKey = PC.ProductCategoryKey
WHERE PC.ProductCategoryKey = 1
AND PC.ProductCategoryKey = 3
ORDER BY C.LastName ASC, FirstName ASC
SELECT FirstName, LastName, EnglishProductCategoryName, COUNT(*)
FROM #temp1
WHERE ProductCategoryKey = 3
GROUP BY FirstName, LastName, EnglishProductCategoryName
HAVING COUNT(*) > 2
I would use a CTE over a temp table unless you have a performance issue. This way you get a single execution plan which is often better (except when its not) than splitting into two execution plans (as using a temp table does).
Also you shouldn't need a distinct unless you have your logic wrong. A correctly grouped query very rarely needs a distinct.
WITH cte AS (
SELECT C.FirstName, C.LastName, PC.EnglishProductCategoryName, PC.ProductCategoryKey
FROM dbo.FactInternetSales AS I
INNER JOIN dbo.DimCustomer AS C ON I.CustomerKey = C.CustomerKey
INNER JOIN dbo.DimProduct AS P ON I.ProductKey = P.ProductKey
INNER JOIN dbo.DimProductSubcategory AS SC ON P.ProductSubcategoryKey = SC.ProductSubcategoryKey
INNER JOIN dbo.DimProductCategory AS PC ON SC.ProductCategoryKey = PC.ProductCategoryKey
WHERE PC.ProductCategoryKey = 1 AND PC.ProductCategoryKey = 3
)
SELECT FirstName, LastName, EnglishProductCategoryName, COUNT(*)
FROM cte
WHERE ProductCategoryKey = 3
GROUP BY FirstName, LastName, EnglishProductCategoryName
HAVING COUNT(*) > 2
ORDER BY LastName ASC, FirstName ASC;
I am assuming the logic is correct, because without sample data and expected results its hard to know.

Getting distinct count in SQL Server

I have three tables:
companies
customers for those companies
addresses for each customer
I want to know how many companies in my database has the accounts with more that 100 addresses linked to them.
I tried this but it didn't work:
SELECT
COUNT(DISTINCT c.Id)
FROM
Customers cu
INNER JOIN
Addresses ad ON ad.Customer = cu.Id
INNER JOIN
Companies c ON cu.company = c.Id
GROUP BY
cu.ID
HAVING
COUNT(ad.ID) > 100
You need two levels of aggregation for this query. Here is one method:
SELECT COUNT(*)
FROM (SELECT cu.company, COUNT(DISTINCT ad.id) as num_accresses
FROM Customers cu
INNER JOIN Addresses ad ON ad.Customer = cu.Id
GROUP BY cu.company
HAVING COUNT(DISTINCT ad.id) > 100
) cua;
The inner query returns the companies that have more than 100 addresses. Note the use of COUNT(DISTINCT). Presumably, two "customers" could have the same addresses.
Also, the companies table is not needed. The identifying information is in customers. You are only looking for a count, so the table is not necessary.

Counting associations from multiple tables

I want to see how many association each of my records in a given table have. Some of these association have some conditions attached to them
So far I have
-- Count app associations
SELECT
distinct a.name,
COALESCE(v.count, 0) as visitors,
COALESCE(am.count, 0) AS auto_messages,
COALESCE(c.count, 0) AS conversations
FROM apps a
LEFT JOIN (SELECT app_id, count(*) AS count FROM visitors GROUP BY 1) v ON a.id = v.app_id
LEFT JOIN (SELECT app_id, count(*) AS count FROM auto_messages GROUP BY 1) am ON a.id = am.app_id
LEFT JOIN (
SELECT DISTINCT c.id, app_id, count(c) AS count
FROM conversations c LEFT JOIN messages m ON m.conversation_id = c.id
WHERE m.visitor_id IS NOT NULL
GROUP BY c.id) c ON a.id = c.app_id
WHERE a.test = false
ORDER BY visitors DESC;
I run into problem with the last join statement for conversations. I want to count the number of conversations that have at least 1 message where the visitor_id is not null. For some reason, I get multiple records for each app, ie. the conversations are not being grouped properly.
Any ideas?
My gut feeling, based on limited understanding of the big picture: in the nested query selecting from conversations,
remove DISTINCT
remove c.id from SELECT list
GROUP BY c.app_id instead of c.id
EDIT: try this
...
LEFT JOIN (
SELECT app_id, count(*) AS count
FROM conversations c1
WHERE
EXISTS (
SELECT *
FROM messages m
WHERE m.conversation_id = c1.id and
M.visitor_id IS NOT NULL
)
GROUP BY c1.app_id) c
ON a.id = c.app_id

Two Inner Joins MYSQL

How would I preform two inner joins in one query?
Ie: three tables
Invoice
Address
Client
Invoice has a column which references an id in clients. It also has a column which references an address. I need to get both the clients name from the matched table and the address from the matched table. How would I INNER JOIN both tables?
I'll add a few details...
invoice has rows address(references address id), client(references client id), id and notes
client has rows first_name, last_name
address has rows street_name and city
I need to pull up
You can have as many JOIN clauses as you need in the query. Each has an ON clause where you specify the related columns between the joined tables.
SELECT
columns
FROM
invoice
INNER JOIN
address
ON
join_condition
INNER JOIN
client
ON
join_condition
Something like:
SELECT
c.*, i.*, a.*
FROM
invoices i
INNER JOIN
client c
ON
i.clientid = c.clientid
INNER JOIN
address a
ON
a.clientid = c.clientid
WHERE
i.id = 21
Don't forget you only select the fields you require, not * (all).
A sample e.g. based on learning from #Dan Grossman above:
SELECT FILM.TITLE, ACTOR.FIRST_NAME, ACTOR.LAST_NAME FROM ACTOR
INNER JOIN FILM_ACTOR
ON ACTOR.ACTOR_ID = FILM_ACTOR.ACTOR_ID
INNER JOIN FILM
ON FILM_ACTOR.FILM_ID = FILM.FILM_ID
WHERE ACTOR.FIRST_NAME = 'Nick' AND ACTOR.LAST_NAME = 'Wahlberg'

How to do a join with multiple conditions in the second joined table?

I have 2 tables. The first table is a list of customers.
The second table is a list of equipment that those customers own with another field with some data on that customer (customer issue). The problem is that for each customer, there may be multiple issues.
I need to do a join on these tables but only return results of customers having two of these issues.
The trouble is, if I do a join with OR, I get results including customers with only one of these issues.
If I do AND, I don't get any results because each row only includes one condition.
How can I do this in T-SQL 2008?
Unless I've misunderstood, I think you want something like this (if you're only interested in customers that have 2 specific issues):
SELECT c.*
FROM Customer c
INNER JOIN CustomerEquipment e1 ON c.CustomerId = e1.CustomerId AND e1.Issue = 'Issue 1'
INNER JOIN CustomerEquipment e2 ON c.CustomerId = e2.CustomerId AND e2.Issue = 'Issue 2'
Or, to find any customers that have multiple issues regardless of type:
;WITH Issues AS
(
SELECT CustomerId, COUNT(*)
FROM CustomerEquipment
GROUP BY CustomerId
HAVING COUNT(*) > 1
)
SELECT c.*
FROM Customer c
JOIN Issues i ON c.CustomerId = i.CustomerId
SELECT *
FROM customers as c
LEFT JOIN equipment as e
ON c.customer_id = e.customer_id --> what you are joining on
WHERE (
SELECT COUNT(*)
FROM equipment as e2
WHERE e2.customer.id = c.customer_id
) > 1
You can do it with a sub query instead of Joins:
select * from Customer C where (select Count(*) from Issue I where I.CustomerID = C.CustomerID) < 2
or whatever value you want