Including NULL results after join - sql-server-2005

I am trying to do a report which shows all payments we have received and for the report I have to show names of patients who pay, but this table also contains checks from payers (insurance companies) and after I do a join all of the payers are excluded. I have tried every join version I know left, right, outer, inner, and combinations of the two. SQL Server 2005.
UPDATE
The line that is causing the left join not to work is
select p.*, max(episode_id) over (partition by patient_id) as maxei from patient p
which I am using in the join. Our system uses an episodic system, so if a patient leaves and comes back they get a new episode. The payment table does not have an episode field though, so I used that line of code in the join to only show the current episode. Any idea how I can keep it only showing the current episode while not losing the fields without patient_id's? Examples of the fields without patients id's are shown in the second image.
select
pay.patient_id,
p.lname + ', ' + p.fname as 'Name',
pay.source_type,
pay.instrument,
pay.doc_reference,
pay.instrument_date,
pay.payment_amount,
pay.user_id,
pay.entry_chron,
pay.payor_id
from payment pay
join (select p.*, max(episode_id) over (partition by patient_id) as maxei from patient p) p
on p.patient_id = pay.patient_id
where episode_id = maxei and (pay.instrument_date between '2014-11-01' and '2014-11-30')
order by pay.payment_amount
This is what the results look like for patients with some fields commented out for confidentiality.
These are the fields that are being excluded

Related

Record with latest date, where date comes from a joined table

I have tried every answer that I have found to finding the last record, and I have failed in getting a successful result. I currently have a query that lists active trailers. I am needing it to only show a single row for each trailer entry, where that row is based on a date in a joined table.
I have tables
trailer, company, equipment_group, movement, stop
In order to connect trailer to stop (which is where the date is), i have to join it to equipment group, which joins to movement, which then joins to stop.
I have tried using MAX and GROUP BY, and PARTITION BY, both of which error out.
I have tried many solutions here, as well as these
https://thoughtbot.com/blog/ordering-within-a-sql-group-by-clause
https://www.geeksengine.com/article/get-single-record-from-duplicates.html
It seems that all of these solutions have the date in the same table as the thing that they want to group by, which I do not.
SELECT
trailer.*
company.name,
equipment_group.currentmovement_id,
equipment_group.company_id,
movement.dest_stop_id, stop.location_id,
stop.*
FROM trailer
LEFT OUTER JOIN company ON (company.id = trailer.company_id)
LEFT OUTER JOIN equipment_group ON (equipment_group.id =
trailer.currenteqpgrpid)
LEFT OUTER JOIN movement ON (movement.id =
equipment_group.currentmovement_id)
LEFT OUTER JOIN stop ON (stop.id = movement.dest_stop_id)
WHERE trailer.is_active = 'A'
Using MAX and GROUP BY gives error "invalid in the select list... not contained in...aggregate function"
Welllllll, I never did end up figuring that out, but if I joined movements on to equipment group by two conditions, all is well. Each extra record was created by each company id.... company id is in EVERY table.

How to return multiple fields from subquery

I work in healthcare where we check a patient's insurance to see if their insurance is still active and is eligible for our services. Unfortunately, the database is not very good at associating the eligibility with an appointment or future visit (we have no control over this). As a result, we do not have visibility into what ultimately happens as a result of that eligibility check (did we use that insurance? did the patient not use insurance at all? etc).
What we'd like to do is try to associate the eligibility to a patient's visit that is within a day of that eligibility check (so same day or day before). I'd like to retrieve that visit number and the primary payer for that visit (I'd like the visit number so I can verify that I'm pulling in the correct visit as well as the correct primary payer).
How do I get both pieces of information in the results of my main query? Alternative: how can I spot check the results to verify it is working as desired if I'm only returning the payer name from an inline subquery?
Eligibility Query
select distinct
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason
from
eligibility elig
inner join payer_mstr pm on elig.payer_id=pm.payer_id
where
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'
Associated Encounter and Payer Data and Tables
select distinct
pe.enc_nbr,
pm.payer_name
from
patient_encounter pe --visit data
--encounter_payer holds payer data for a specific visit, and 1 means primary payer
left join encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
left join payer_mstr pm on epay.payer_id=pm.payer_id
I'm on Microsoft SQL Server 2008 R2
You could try using a common table expression. Works like a subquery and you can add all the fields you would like to have from it.
Common Table Expressions
WITH cte AS (
select
pe.enc_nbr,
pm.payer_name,
pm.payer_id,
ROW_NUMBER() OVER(PARTITION BY pm.payer_id ORDER BY pm.payer_id ASC) AS row_num --If you have a date created on each row I would change the pm.payer_id field that and change it to ORDER BY <field> DESC
from
patient_encounter pe --visit data
--encounter_payer holds payer data for a specific visit, and 1 means primary payer
left join encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
left join payer_mstr pm on epay.payer_id=pm.payer_id
--Here you could add a WHERE clause to narrow your search date down to get previous or current date if you have a date field just use WHERE date >= DATEADD(d,-1,GETDATE())
)
select distinct
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason,
cte.enc_nbr
from
eligibility elig
inner join payer_mstr pm on elig.payer_id=pm.payer_id
left join cte ON cte.pm.payer_id = pm.payer_id --Now you can pull in any fields you need and can see if they have a record or do not
where
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'
Hard to test your very specific question, but try this:
SELECT DISTINCT
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason
pe.enc_nbr
FROM
patient_encounter pe
LEFT JOIN encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
LEFT JOIN payer_mstr pm on epay.payer_id=pm.payer_id
LEFT JOIN eligibility elig on elig.payer_id=pm.payer_id
WHERE
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'

calculates between These two columns in SQL server [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I want to add a column to the query that calculates between These two columns In the same query ....................................................................
,isnull(sum(ORDERS.Net_Amount) + 0,0) as orders
,isnull(sum (convert(float,(RECEIPTS.Amount))) + 0,0) as recepts
IN SQL SERVER
SELECT CUSTOMERS.[ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,isnull(sum(ORDERS.Net_Amount) + 0,0) as orders
,isnull(sum (convert(float,(RECEIPTS.Amount))) + 0,0) as recepts
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,CUSTOMERS.[state]
FROM [CUSTOMERS]
LEFT JOIN ORDERS on CUSTOMERS.ID_CUSTOMER = ORDERS.CUSTOMER_ID
LEFT JOIN RECEIPTS on CUSTOMERS.ID_CUSTOMER = RECEIPTS.ID_CUSTOMER
GROUP BY CUSTOMERS.[ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,CUSTOMERS.[state]
CUSTOMERS table
SELECT [ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,[IMAGE_CUSTOMER]
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,[Balance]
,[state]
FROM [CUSTOMERS]
ORDERS table
SELECT [ID_ORDER]
,[DATE_ORDER]
,[CUSTOMER_ID]
,[DESCRIPTION_ORDERS]
,[SALEMAN]
,[ORDER_TOTAL]
,[Discount_Of_Total]
,[Total_After_Discount]
,[Paid_Up]
,[Net_Amount]
,[state]
FROM [ORDERS]
RECEIPTS table
SELECT [image_state]
,[ID_RECEIPT]
,[ID_CUSTOMER]
,[Date]
,[Ref]
,[Amount]
,[Memo]
,[User_Name]
,[state]
,[Payment_Method]
,[Account_ID]
FROM [RECEIPTS]
Orders and receipts are not really related to each other (the receipt doesn't refer to a specific order), so don't join the two. What you want to do instead is find the order amount and the receipt amount per customer and show them. So aggregate the two tables per customer and outer-join the results to the customer table.
select
c.id_customer,
c.first_name,
c.tel,
c.email,
coalesce(o.sum_net_amount, 0) as order_amount,
coalesce(r.sum_amount, 0) as receipt_amount,
c.cridit_limit,
c.customer_since,
c.adress,
c.balance,
c.state
from customers c
left join
(
select customer_id, sum(net_amount) as sum_net_amount
from orders
group by customer_id
) o on c.id_customer = o.customer_id
left join
(
select id_customer, sum(amount) as sum_amount
from receipts
group by id_customer
) r on c.id_customer = r.id_customer;
I see you have updated your request now asking also for the difference of the sums. Well, the operator for subtraction in SQL is - little surprising - the minus sign:
coalesce(o.sum_net_amount, 0) - coalesce(r.sum_amount, 0) as diff
Please try the following...
SELECT Customers.ID_Customer,
first_name,
tel,
email,
SUM( net_amount ) AS OrdersTotal,
COALESCE( sumAmount, 0 ) AS PaymentsTotal,
SUM( net_amount ) - COALESCE( sumAmount, 0 ) AS DifferenceInTotals,
cridit_limit,
customer_since,
adress,
balance,
state
FROM Customers
INNER JOIN Orders ON Customers.ID_Customer = Orders.Customer_ID
LEFT JOIN ( SELECT ID_Customer,
SUM( amount ) AS sumAmount
FROM Receipts
GROUP BY ID_Customer
) AS sumAmountFinder ON Customers.ID_Customer = sumAmountFinder.ID_Customer
GROUP BY Customers.ID_Customer,
first_name,
tel,
email,
cridit_limit,
customer_since,
adress,
balance,
state;
This Answer is based on the assumption that every Customer will have at least one Order, but possibly no Receipts.
This statement is essentially the one that you supplied with the following modifications...
I have changed the JOIN to Orders to an INNER JOIN, since I am assuming that each Customer will have at least one Order. The LEFT JOIN is only necessary where you wish to retain all records from the left table that do not have at least one matching record from the right table as defined by the ON clause. (Note : If you wish to retain all the records from the right table where there is no matching records from the left table, use a RIGHT JOIN).
I have replaced the JOIN to the Receipts table with a subquery that calculates the total of the amount field for each Customer in the Receipts table. A LEFT JOIN is necessary between Customers and the results of this subquery as not all Customers will have a Receipt. In such situations the LEFT JOIN will set each of the fields from the subquery in the joined dataset to NULL.
Where the SUM() function encounters only NULL values it returns NULL, not 0. So that PaymentsTotal will be set to 0 for records where the Customer has no Receipts, I have used the COALESCE() function. This function will return the first non-NULL argument it encounters. Here I have set it to return the total of amount where it encounters one, and 0 where it encounters no total amount.
I have removed all of the square brackets from your field and table names. They are only required where you have used an otherwise disallowed name, such as names with spaces (use [Full Name] instead of Full Name) or names that are also reserved by SQL-Server (if you had decided to call PaymentsTotal Sum, then you would have had to use AS [Sum]). Many programmers consider giving fields such names to be bad practice, even when it is possible with []'s, but fortunately you have not used any otherwise names.
I have removed the table names from your SUM() calculations. Since only one table has a field called net_amount, then it will be a unique field name in the joined dataset, and you will be able to refer to them without specifying the name of the source table as well. Specifying the source table is still necessary in the case of Customers.ID_Customer as the joined dataset will have more than one field called ID_Customer. Also, you will need to specify the source tables names when creating the joined dataset using the JOIN's.
I have also taken the liberty of changing your capitalisation scheme. Having just about everything in constant upper-case is monotonous to the eye. Using different casing for SQL terms, table names and field names makes recognising each type of statement part much easier, and thus makes debugging code much easier.
Finally, and relatively trivially, cridit is actually spelt credit and adress is actually spelt address.
If you have any questions or comments, then please feel free to post a Comment accordingly.

Summing Sales Data Access

I'm just starting out with SQL, I have been playing around with simple select queries and grouping data, now I want to pull some actually useful data out of our database for analysis. The data is organized as follows:
Access 2010 Database
I didn't set it up, I know it isn't set up as it should be
I can't change data, only poll
-Customers are kept in one table
-Closed orders are kept in another table (each line item is listed with invoice #, date closed, Customer ID as well as other info)
-Archived closed orders table keep sales records that are a year + old (table is laid out exactly the same as Closed order table)
I want to start with a simple query, list all the customers from a certain branch and their past year totals. Here's what I have tried:
SELECT CUSTOMERS.Company, CUSTOMERS.[Ship City], (SELECT SUM (CLOSEDORDERS.Quant*CLOSEDORDERS.SellPrice) FROM CLOSEDORDERS WHERE CUSTOMERS.ID = CLOSEDORDERS.CustID) AS LifeTotal
FROM CUSTOMERS, CLOSEDORDERS
WHERE CUSTOMERS.Branch=33;
When I run the query, it asks me to enter a parameter value for CLOSEDORDERS.Quant. What am I doing wrong?
I think this is what you're looking for with an OUTER JOIN:
SELECT CUSTOMERS.Company,
CUSTOMERS.[Ship City],
SUM(CLOSEDORDERS.Quant*CLOSEDORDERS.SellPrice) AS LifeTotal
FROM CUSTOMERS
LEFT JOIN CLOSEDORDERS ON CUSTOMERS.ID = CLOSEDORDERS.CustID
WHERE CUSTOMERS.Branch=33
GROUP BY CUSTOMERS.Company,
CUSTOMERS.[Ship City]
If you only want to return matching results from both tables, then use a standard INNER JOIN instead of the LEFT JOIN.

Getting records from three tables with sometimes unmatching fields

I have a question that should be easy to answer...
I have a table called Projects, primary key is ProjectId.
Second table is called ProjectResources, with ProjectId as a foreign key, plus fields for user and hours (represents the users assigned to work on the project)
Third table is TimesheetEntries (which the users use to record hours users actually worked on a project), with ProjectId as foreign Key, and field User
What is required is for me to show the records of the projectId,BudgetedHours (from ProjectResources table) and ActualHours (from the TimesheetEntries table); I would like however to include the following cases where:
a user was assigned to the project but did not work on it (in this case the budgeted hours should have a value and the actual hours should have zero)
a user was not assigned to the project but has nonetheless worked on it (in which case the BudgetedHours should be zero and the ActualHours should have a value)
a user was both assigned to the project and has worked on it (both BudgetedHours and ActualHours have values)
Could somebody direct me to a T-SQL statement to get this kind of result?
You could try something like:
SELECT p.ProjectId,
(CASE WHEN pr.[User] Is NULL THEN te.[User] ELSE pr.[User] END) as [User],
IsNull(pr.BudgetedHours, 0.0),
IsNull(Sum(te.ActualHours), 0.0)
FROM Project p
LEFT JOIN ProjectResources pr on p.ProjectId = pr.ProjectId
LEFT JOIN TimeSheetEntries te on p.p.ProjectId = te.ProjectId
GROUP BY p.ProjectId, te.User, pr.BudgetedHours
But I'm guessing at your field names, etc. so you would need to adapt this for your own domain.
I think the reason you are having problems is because you are thinking about the actual hours and the budgeted hours as being all essentially equal, because they are assigned to the project.
However, the actual and budgeted are calculated in very different ways. You need to calculate them using separate subqueries, as in the following example:
select coalesce(budget.ProjectId, actual.ProjectId) as ProjectId,
budget.BudgetedHours, actual.ActualHours
from
(
select projectid, sum(pr.hours) as BudgetedHours
from Projects p
left outer join ProjectResources pr
) budget
full outer join
(
select projectid, sum(tse.hours) as ActualHours
from Projects p
left outer join TimeSheetEntries tse
on tse.ProjectId = p.ProjectId
) actual
on budget.ProjectId = actual.ProjectId