SQL Coding, Unable to Limit based on where in subquery - sql

I have a query I'm writing, and it's nearly perfect, excepting one error I can't seem to control for.
SELECT Clients.client_id,
Clients.last_name + ', ' + Clients.first_name AS Client_Name,
Query3.team_id,
Query3.team_name,
Query2.CSW_Name,
Query1.Date_of_Service AS Last_Service_by_CSW,
Query.Tx_Start_Date AS Tx_Start_Date,
Query.Tx_End_Date AS Tx_End_Date
FROM Clients
LEFT OUTER JOIN
(SELECT TxPlus.client_id,
Max(TxPlus.start_date) AS Tx_Start_Date,
Max(TxPlus.end_date) AS Tx_End_Date
FROM TxPlus
GROUP BY TxPlus.client_id) Query ON Query.client_id = Clients.client_id
LEFT OUTER JOIN
(SELECT EmployeeClients.client_id,
Employees.last_name + ', ' + Employees.first_name AS CSW_Name
FROM EmployeeClients
INNER JOIN Employees ON EmployeeClients.emp_id = Employees.emp_id
WHERE EmployeeClients.case_manager = 1) Query2 ON Clients.client_id = Query2.client_id
LEFT OUTER JOIN
(SELECT ClientVisit.client_id,
Max(ClientVisit.rev_timeout) AS Date_of_Service
FROM ClientVisit
INNER JOIN EmployeeClients ON ClientVisit.emp_id = EmployeeClients.emp_id
GROUP BY ClientVisit.client_id,
EmployeeClients.case_manager,
ClientVisit.visittype_id
HAVING EmployeeClients.case_manager = 1
AND ClientVisit.visittype_id = 9) Query1 ON Clients.client_id = Query1.client_id
LEFT OUTER JOIN
(SELECT TeamClient.client_id,
Team.team_id,
Team.team_name
FROM TeamClient
INNER JOIN Team ON TeamClient.team_id = Team.team_id
WHERE TeamClient.primary_flag = 1) Query3 ON Clients.client_id = Query3.client_id
WHERE Clients.client_status LIKE 'Active'
The objective is to basically pull a client record, and show the dates for their Treatment Plan, their Primary Team Assignments, their case manager, and the most Community Support service there case manager provided for them.
Right now, with the code as it's written, I get all the correct information, EXCEPT the most recent Community Support date. This returns the most recent service done by ANYONE, not the Case Manager.
I'm certain its a very simple problem, but it's driving me up the wall.
You all are an invaluable resource, and I thank you in advance.

Well, without knowing what the data looks like, I can't be 100% certain that this is the answer, but I have a pretty good feeling about it. I believe that this is the query that is returning your, "Community Support Date". (It wasn't identified as clearly as I would have liked, but it looks to me like this is it.)
(SELECT ClientVisit.client_id,
Max(ClientVisit.rev_timeout) AS Date_of_Service
FROM ClientVisit
INNER JOIN EmployeeClients ON ClientVisit.emp_id = EmployeeClients.emp_id
GROUP BY ClientVisit.client_id,
EmployeeClients.case_manager,
ClientVisit.visittype_id
HAVING EmployeeClients.case_manager = 1
AND ClientVisit.visittype_id = 9) Query1 ON Clients.client_id = Query1.client_id
So what you're doing is creating a subset of the data in these two tables, joined by emp_id and grouped by client, case manager and visit type. Then you remove any groups that are not the case manager or visit type you want. But by this point, you've already selected your Max(ClientVisit.rev_timeout) AS Date_of_Service. I believe that if you change your HAVING clause into a WHERE clause (and thus filter before you group) you will get the results you're looking for.
EDIT:
(SELECT ClientVisit.client_id,
Max(ClientVisit.rev_timeout) AS Date_of_Service
FROM ClientVisit
INNER JOIN EmployeeClients ON ClientVisit.emp_id = EmployeeClients.emp_id
WHERE EmployeeClients.case_manager = 1
AND ClientVisit.visittype_id = 9
GROUP BY ClientVisit.client_id) Query1 ON Clients.client_id = Query1.client_id

Related

Creating a query for a report to bring in clients only if they have open accounts

I have a query I am trying to use to give my users a list of only clients that currently have open accounts. The issue I am having is that it is bringing in ALL clients even if they do not have any current accounts. I feel like I am missing something simple here but so far have not been able to get this to work as intended.
SELECT Client.Client
FROM dbo.Client
LEFT JOIN dbo.ClientLink On Client.Client = ClientLink.Client
LEFT JOIN dbo.ClientLink.ExternalId = AccountLink.ExternalId
LEFT JOIN dbo.AccountLink.Account = Account.Account
GROUP By Client.Client
HAVING SUM(CASE WHEN Account.Closed IS NULL THEN 1 ELSE 0 END) > 0
My guess is that if clients have no accounts, then the links between the tables may be removed. If so, the solution is to simply use INNER JOIN.
Your syntax is also all messed up. But the query you want might be:
SELECT c.Client
FROM dbo.Client c JOIN
dbo.ClientLink cl
AccountLink al
ON cl.ExternalId = al.ExternalId JOIN
Account a
ON a.Account = al.Account
GROUP By c.Client
HAVING SUM(CASE WHEN Account.Closed IS NULL THEN 1 ELSE 0 END) > 0
My advice would be to rethink your query and how you are storing your data this is fundamental get this wrong then querying the database becomes a nightmare and you get unexpected results for example does Account.Closed need to be null? if this was me I would create a default constraint that would set new accounts to be 0 (meaning open) then write a query to update accounts that needed to be closed and set this to 1.
again without really knowing how your schema looks providing an accurate answer is difficult.
I would then re-write the query to be.
SELECT Client.Client
FROM dbo.Client
LEFT JOIN dbo.ClientLink On Client.Client = ClientLink.Client
LEFT JOIN dbo.ClientLink.ExternalId = AccountLink.ExternalId
LEFT JOIN dbo.AccountLink.Account = Account.Account
WHERE Account.Closed = 0 --only return clients with opened accounts
if this is not possible to do then I would re-write your query as follows:
SELECT Client.Client, COUNT(Client.Client) AS NumberOfOpenAccounts
FROM dbo.Client
LEFT JOIN dbo.ClientLink On Client.Client = ClientLink.Client
LEFT JOIN dbo.ClientLink.ExternalId = AccountLink.ExternalId
LEFT JOIN dbo.AccountLink.Account = Account.Account
WHERE ISNULL(Account.Closed, 1) = 0 --only return clients with opened accounts
GROUP BY Client.Client
If all you are looking for is the client name, you can use DISTINCT instead of grouping. Something like the below statement might do the trick:
SELECT Distinct Client.Client
FROM Client
INNER JOIN ClientLink On Client.Client = ClientLink.Client
INNER JOIN AccountLink On ClientLink.ExternalId = AccountLink.ExternalId
INNER JOIN Account on AccountLink.Account = Account.Account
WHERE Account.Closed IS NULL
Hope this helps.

SQL Query to get list of services in one program if the client is also in another program

I am looking to pull a list of medical services for clients that are in two programs. What I need is, if the client is in Wraparound program, I need to pull a list of services they've received in the MH program for a specified date range.
SELECT cv.client_id,
cv.clientvisit_id,
Programs.program_desc,
Clients.text1 As Client,
cv.visittype,
cv.duration,
cv.non_billable,
cv.timein as event_date,
Employees.last_name
FROM clientvisit cv
Inner Join programs On programs.program_id = cv.program_id
Inner Join Clients On Clients.client_id = cv.client_id
Inner Join Employees On Employees.emp_id = cv.emp_id
WHERE programs.program_desc = 'MH' AND (SELECT cv.client_id from
clientvisit WHERE programs.program_desc = 'Wraparound') AND
(cv.timein >= #param1 AND cv.timein <= #param2)
Putting part of the question as an answer is really confusing, but the problem you're having is this bit:
AND (SELECT cv.client_id from
clientvisit WHERE programs.program_desc = 'Wraparound') AND
The sub-select is return an id of some kind, but you're trying to do an AND against it.
I'm guessing you mean to compare that id against something, so something like
AND (SELECT cv.client_id from
clientvisit WHERE programs.program_desc = 'Wraparound') = {id you want to compare to} AND

How to Distinct a sql query but still return all columns

This is my query:
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId,
dbo.Roles.Title AS RoleTitle, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment
INNER JOIN dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId
AND dbo.RoleAssignment.RoleId = dbo.Roles.RoleId
INNER JOIN dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId
AND dbo.Roles.WebId = dbo.Webs.Id
INNER JOIN dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
WHERE tp_Title = 'HOBSON, Will';
This database contains all the permissions for the users of all sharepoint sites. I'm trying to create a query that displays all sites the user has access to. Currently it outputs a lot of duplicate information. I only want it to display results that have either a distinct Role Title or a distinct Web id.
So for example, in this query I would only want to see 4 results; 1, 5, 11 and 13.
(all this information is on a local test SharePoint installation that cannot be accessed externally, so the only information I'm giving away here is my name :))
Your query would be much easier to read with table aliases. The direct answer to your question is to use SELECT DISTINCT:
SELECT DISTINCT w.Id, w.Title, w.FullUrl, r.RoleId, r.Title AS RoleTitle,
ui.tp_Title, ui.tp_Login
FROM dbo.RoleAssignment ra INNER JOIN
dbo.Roles r
ON ra.SiteId = r.SiteId AND
ra.RoleId = r.RoleId INNER JOIN
dbo.Webs w
ON r.SiteId = w.SiteId AND
r.WebId = w.Id INNER JOIN
dbo.UserInfo ui
ON ra.PrincipalId = ui.tp_ID
WHERE tp_Title = 'HOBSON, Will';
However, it would be better to find the cause of the duplicates. Often duplicates like this are caused by incomplete join conditions. Fixing the join is the better approach, but sometimes SELECT DISTINCT is necessary.
You can just add a DISTINCT to your query:
SELECT DISTINCT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId,
dbo.Roles.Title AS RoleTitle, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment
INNER JOIN dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId
AND dbo.RoleAssignment.RoleId = dbo.Roles.RoleId
INNER JOIN dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId
AND dbo.Roles.WebId = dbo.Webs.Id
INNER JOIN dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
WHERE tp_Title = 'HOBSON, Will';

SQL Select every row in table1 that has a row in table2

I have two tables, one for users, and one for renewals. I want to select all users who have a row in the renewals table for a specific year, and I can do this fine. However, if there are more than one row for a specific user for the specific year in the renewals table, I get duplicates, which I don't want.
I assume it's because I still don't quite understand JOINS, so here is my query:
SELECT * FROM `users` AS US
RIGHT JOIN `usermeta` UM1
ON UM1.`user_id` = US.`ID`
RIGHT JOIN `membership_renewals` MR
ON MR.`user` = US.`ID` AND MR.year = '2011'
WHERE
UM1.meta_key = 'member'
AND UM1.meta_value = 1
AND US.`user_pass` NOT LIKE '-%'
You can do it with JOINS, but I like to do this kind of thing with EXISTS and subqueries, because it reads more like the rule I am trying to enforce.
SELECT * FROM `users` AS US
RIGHT JOIN `usermeta` UM1
ON UM1.`user_id` = US.`ID`
WHERE
Exists (Select 1 FROM `membership_renewals` MR
WHERE MR.`user` = US.`ID`
AND MR.year = '2011')
AND UM1.meta_key = 'member'
AND UM1.meta_value = 1
AND US.`user_pass` NOT LIKE '-%'
P.S. I really don't like using RIGHT JOIN unless I have to. If you can, just user INNER JOIN. If not, rearrange the FROM so you can use LEFT JOIN. Again, it is just for readability, but I don't know that i have ever used RIGHT JOIN.
SELECT *
FROM `users` AS US
RIGHT JOIN `usermeta` UM1
ON UM1.`user_id` = US.`ID`
RIGHT JOIN (select distinct mr.user from `membership_renewals` MR where MR.year = '2011') vt on vt.user = us.id
WHERE UM1.meta_key = 'member'
AND UM1.meta_value = 1
AND US.`user_pass` NOT LIKE '-%'
This will do it.

Selecting the first row out of many sql joins

Alright, so I'm putting together a path to select a revision of a particular novel:
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
ON HasNovelRevision.Left=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.Right
WHERE Catalog.obid = BookInCatalog.Left;
This returns all revisions that are in the Novel Master for each Novel Master that is in the catalog.
The problem is, I only want the FIRST revision of each novel master in the catalog. How do I go about doing that? Oh, and btw: my flavor of sql is hobbled, as many others are, in that it does not support the LIMIT Function.
****UPDATE****
So using answer 1 as a guide I upgraded my query to this:
SELECT Catalog.wbsid
FROM Catalog, BookInCatalog, NovelVersion old, NovelMaster, HasNovelRevision
LEFT JOIN NovelVersion newRevs
ON old.revision < newRevs.revision AND HasNovelRevision.right = newRevs.obid
LEFT JOIN HasNovelRevision NewerHasNovelRevision
ON NewerHasNovelRevision.right = newRevs.obid
LEFT JOIN NovelMaster NewTecMst
ON NewerHasNovelRevision.left = NewTecMst.obid
WHERE Catalog.programName = 'E18' AND Catalog.obid = BookInCatalog.Left
AND BookInCatalog.right = NewTecMst.obid AND newRevs.obid = null
ORDER BY newRevs.documentname;
I get an error on the fourth line:
"old"."revision": invalid identifier
SOLUTION
Well, I had to go to another forum, but I got a working solution:
select nr1.title, nr1.revision
from novelrevision nr1
where nr1.revision in (select min(revision) from novelrevision nr2
where nr1.title = nr2.title)
So this solution uses the JOIN mentioned by the OA, along with the IN keyword to match it to a revision.
Something like this might work, it's called an exclusive left join:
....
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
...
WHERE NeverRevision.obid is null
The where clause filters out rows for which a newer revision exists. This effectively limits the query to the newest revisions.
In response to your comment, you could filter out only revisions that have a newer revision in the same NovelMaster. For example:
....
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
LEFT JOIN HasNovelRevision as NewerHasNovelRevision
ON NewerHasNovelRevision.right = NewerRevision.obid
LEFT JOIN NovelMaster as NewerNovelMaster
ON NewerHasNovelRevision.left = NewerNovelMaster.obid
AND NewerNovelMaster.obid = NovelMaster.obid
....
WHERE NeverNovelMaster.obid is null
P.S. I don't think you can group JOINs and follow them with a group of ON conditions. An ON must directly follow its JOIN.
You can use CTE
Check this
WITH NovelRevesion_CTE(obid,RevisionDate)
AS
(
SELECT obid,MIN(RevisionDate) RevisionDate FROM NovelRevision Group by obid
)
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevesion
INNER JOIN NovelRevesion_CTE
ON HasNovelRevision.[right] = NovelRevision.obid
ON HasNovelRevision.[Left]=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.[Right]
ON NovelRevesion_CTE.obid = NovelRevesion.obid
WHERE Catalog.obid = BookInCatalog.[Left];
First it select the first revision written for each novel (assuming obid is novel foriegn key) by taking the smallest date and group them.
then add it as join in your query