Combine 2 SQL SELECT statements - sql

** Evidently some people think my question is not worthy of their time. I whole heartedly appologise for this. However, rather than down voting why not use that time to do something positive and at least tell me what info you would require to make this not be a cr#p question in your eyes. **
I have a list of staff in table tblMembers and a list of clients in table tblClients.
One person may have several client.
The staff member associated with a client is identified by staffId against the client record.
Each staff member has a category Id for the type of clients they have catId.
I need to find all of the staff for a given client type and then sort them by the number of clients they have. Staff members without any clients should show a result of 0 rather than not showing.
A simplified table structure would be:
tblMembers:
Id | catId
tblClients:
Id | staffId
Any help would be greatly appreciated.
Thanks!

Try this:
SELECT m.Id 'Member Id', ISNULL(c.StaffCount, 0) 'StuffCount'
FROM tblMembers m
LEFT JOIN
(
SELECT staffId, COUNT(staffId) 'StaffCount'
FROM tblClients
GROUP BY staffId
) c ON m.Id = c.staffId
WHERE m.Cat = 'Some Id'
ORDER BY StuffCount

Its fairly simple to do a join/group and count
SELECT
s.id,
s.catid,
COUNT(c.id)
FROM
tblMembers s
LEFT JOIN tblClients c
ON s.id = c.staffid
WHERE
s.catid = #catID
GROUP BY
s.id,
s.catid
ORDER BY
COUNT(c.id) desc
However the one tricky bit is
show a result of 0 rather than not showing.
To do this you need to do a left join to make sure they show even if there are no matching records and you need to make sure to count a field on the table on the Right side of the join. Otherwise you'd get a count of 1
DEMO

Hope I correctly understood your case.
Try something like this:
SELECT T1.ID,
Count(*)
FROM MEMBERS T1
INNER JOIN CLIENTS T2
ON T1.ID = T2.STAFFID
WHERE T1.CATID = 2
GROUP BY T1.ID
UNION
SELECT DISTINCT ID,
0
FROM MEMBERS
WHERE CATID != 2
A working sample is available here.

try:
select tblMembers.id, count(tblClient.id)
from tblMembers left join tblCLient on staffId = tblMembers.id
where tblMembers.catId = ??
group by tblMembers.id
order by 2 desc

Related

Showing customers who have purchased more than 1 product, but from the same subscription

I'm trying to find the number of customers who have ordered more than one product, with the same subscription.
I've first selected the count of the id_customer from customer. Then joined on subscription and order (on the correct keys). This was done so that I have all the data available to me from all 3 tables. Then grouped by the id_customer to get just the unique customers. And lastly filtered to have a fk_product (products a customer has) greater than 1.
SELECT COUNT(t1.id_customer)
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer
HAVING COUNT(t3.fk_product) > 1
I'd like to better understand if this is the correct syntax to obtain the data I'm looking for. Since I have t2.id_subscription and t3.fk_subscription linked, wouldn't this be correct? I'm still getting the wrong output. I'm thinking its perhaps the way I have my scopes, or some subtle aspect of SQL that I'm not using/understanding.
Thank you for your help!!
Use two levels of aggregation. Your data model is a bit hard to follow, but I think:
SELECT COUNT(DISTINCT so.fk_customer)
FROM (SELECT s.fk_customer, s.id_subscription
FROM subscription s
order o
ON s.id_subscription = o.fk_subscription
GROUP BY s.fk_customer, s.id_subscription
HAVING MIN(o.fk_product) <> MAX(o.fk_product)
) so
select count(distinct s.id_customer)
from (
SELECT t1.id_customer
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer, t3.fk_subscription
HAVING COUNT(1) > 1
) s

Select one record from a nested sql select

Help - I have puzzeled on this for some time and am going bats.
In this cutdown query I want to select a single Email address from a contacts list that may contain multiple contacts for that customer.
My problem is that it does not find the Contacts email if I specify TOP 1
(showing NULL for CC.Email)
Note: it returns two records with Contact emails if I specify TOP 5
I think the TOP 1 must be restricting the records to 1 before determining a match?
SELECT C.Code as Customer, C.Name as CustomerName, C. Email, CC.Email, IIF(CC.Email<>'',CC.Email,C.Email) as Email
FROM [dr].[Customer] C
LEFT OUTER JOIN (Select TOP 1 CustomerId, Email
from dr.Contact CC
INNER JOIN dr.ContactDocumentOption CDO
on CDO.TransactionTypeId = 102
AND CDO.ContactId = CC.ContactId
Order by CC.ContactId) CC
on CC.CustomerId = C.CustomerId
WHERE C.Code = 'B82'
Well, it's a bit hard to understand your question, but i guess you have multiple rows of the same customer, but not every row has values in the email column, am I right?
For this you should try including WHERE Email IS NOT NULL in your SQL string, the part with TOP 1 is good, but try to make the SQL statement return values only if it finds an email, using Email IS NOT NULL.
I hope I understood your question and that this helps you.
Have you tried to LEFT JOIN directly the second request instead of using a nested request? And then you take TOP 1 on the main request?
It would be easier to help if you had a SQL fiddle.
You can combine the data from Contacts with [SQL Row_Number() function][1] and additional Partition By clause as follows
Please note instead of TOP, I used Row_number function and used the result in WHERE clause with rn=1 for choosing the top 1
;with cte as (
select
c.Code as Customer, c.Name as CustomerName, c.Email CustomerEmail, cc.Email ContactEmail,
rn = ROW_NUMBER() over (partition by c.CustomerId order by cc.Email desc)
from Customer c
left join Contact cc on c.CustomerId = cc.CustomerId
left join ContactDocumentOption o on o.TransactionTypeId = 102
and o.ContactId = cc.ContactId
where c.Code = 'B82'
)
select Customer, CustomerName, ISNULL(ContactEmail,CustomerEmail) Email
from cte where rn = 1
ISNULL() function is a better way to compare two fields according to one of the field's nullable case
Output is as follows

SQL select with join are returning double results

I am trying to select some data from different tables using join.
First, here is my SQL (MS) query:
SELECT Polls.pollID,
Members.membername,
Polls.polltitle, (SELECT COUNT(*) FROM PollChoices WHERE pollID=Polls.pollID) AS 'choices',
(SELECT COUNT(*) FROM PollVotes WHERE PollVotes.pollChoiceID = PollChoices.pollChoicesID) AS 'votes'
FROM Polls
INNER JOIN Members
ON Polls.memberID = Members.memberID
INNER JOIN PollChoices
ON PollChoices.pollID = Polls.pollID;
And the tables involved in this query is here:
The query returns this result:
pollID | membername | polltitle | choices | votes
---------+------------+-----------+---------+-------
10000036 | TestName | Test Title| 2 | 0
10000036 | TestName | Test Title| 2 | 1
Any help will be greatly appreciated.
Your INNER JOIN with PollChoices is bringing in more than 1 row for a given poll as there are 2 choices for the poll 10000036 as indicated by choices column.
You can change the query to use GROUP BY and get the counts.
In case you don't have entries for each member in the PollVotes or Polls table, you need to use LEFT JOIN
SELECT Polls.pollID,
Members.membername,
Polls.polltitle,
COUNT(PollChoices.pollID) as 'choices',
COUNT(PollVotes.pollvoteId) as 'votes'
FROM Polls
INNER JOIN Members
ON Polls.memberID = Members.memberID
INNER JOIN PollChoices
ON PollChoices.pollID = Polls.pollID
INNER JOIN PollVotes
ON PollVotes.pollChoiceID = PollChoices.pollChoicesID
AND PollVotes.memberID = Members.memberID
GROUP BY Polls.pollID,
Members.membername,
Polls.polltitle
You are getting 1 row for each PollChoices record since there are multiple choices per Polls INNER JOIN Members. You may be expecting the SELECT COUNT(*) sub-queries to act as a GROUP BY clause, but they don't.
If that doesn't make sense, add a bare minimum of sample data and the expected result and we can help more.
This query result is telling you the number of votes per choice in each poll.
In your example, this voter named TestName answered the poll (with ID 10000036) and gave one choice 1 vote, and the second choice 0 votes. This is why you are getting two rows in your result.
I'm not sure if you are expecting just one row because you didn't specify what data, exactly, you are trying to select. However if you are trying to see the number of votes that TestName has submitted, for each choice where the vote was greater than 1, then you will have to modify your query like this:
select * from
(SELECT Polls.pollID,
Members.membername,
Polls.polltitle, (SELECT COUNT(*) FROM PollChoices WHERE pollID=Polls.pollID) AS 'choices',
(SELECT COUNT(*) FROM PollVotes WHERE PollVotes.pollChoiceID = PollChoices.pollChoicesID) AS 'votes'
FROM Polls
INNER JOIN Members
ON Polls.memberID = Members.memberID
INNER JOIN PollChoices
ON PollChoices.pollID = Polls.pollID) as mysubquery where votes <> 0;

SQL query help - Join on second table, possible?

Two questions.
One: How would I be able to join two tables together, which are not the original FROM 'x' table?
Example: Grabbing all the reports and that users level name.
Report
id | user_id
1 1
User
id | level_id
1 1
Level
id | level_name
1 Admin
SELECT report.id,
report.user_id,
level.name
FROM report
INNER JOIN user
ON report.user_id=user.id
INNER JOIN level
ON user.level_id=level.id
Doesn't seem to work.
Two: How to join tables not from a 1-1 but a 1-many?
Say I wanted to:
SELECT * FROM user JOIN report ON user.id=report.user_id WHERE user.id='4'
But only join with the most recent report ordered by date desc?
I know it seems like I am asking you to do my work for me, but I just need to know what to use to accomplish this, not necessarily you coding it. Thanks.
UPDATE:
First question: Fixed, thanks
Second question:
I'll show you my query to make better sense, I didn't explain it well. I meant a many-many relationship where I grab a list of users and their latest report!
SELECT
user.id
FROM
user
<< INNER JOINS ON OTHER TABLES >>
INNER JOIN
(
SELECT
report.id
FROM
report
WHERE user.id=report.user_id
ORDER BY
date
DESC
LIMIT 1
)
For your second question:
MySQL-style:
SELECT *
FROM user
INNER JOIN report re
ON re.id = (SELECT id
FROM report
WHERE user_id=user.id
ORDER BY report.date DESC
LIMIT 1)
WHERE user.id='4'
One: Looks good to me, but shouldn't that be level.level_name in the SELECT clause?
Two: If you just want the most recent report it would be something like...
SELECT TOP 1 * FROM user JOIN report ON user.id=report.user_id WHERE user.id='4' order by report.date desc

Sub-Query Problem

I have two tables like this
Member and their Purchases
I need the output like this
Member_ID | CountofProducts
(and the Product Value not should be 0 and Purchase Status = 1)
SELECT
MemberName,
(SELECT COUNT(*) AS Count
FROM dbo.Purchases
WHERE MemberName = dbo.Members.MemberName
AND Res_Status = 1) AS Count
FROM
dbo.Members
I can get their total CountofPurchased Products from the above query but I need to avoid their count=0 how to do it ?
You can try something like
SELECT m.MemberName,
COUNT(p.*) Cnt
FROM Members m INNER JOIN
Purchases p ON m.MemberName = p.MemberName
WHERE p.Res_Status = 1
GROUP BY m.MemberName
There is no need for the HAVING clause, as the INNER JOIN will exclude all entries in Members that do not have Purchases.
SELECT m.MemberName, COUNT(p.*) AS CountOfProducts
FROM Members m
INNER JOIN Purchases p ON m.MemberName = p.MemberName
WHERE p.Res_Status = 1
GROUP BY m.MemberName
HAVING COUNT(p.*) > 0
I think the above will somewhat do what you want. The key is that you probably do not even need your subquery, but rather you can handle the query (possibly with greater efficiency) just using a join.