Complex SQL query. At least for me - mysql

I am trying to pull invoice data from my database based on a PatientID. I am trying to figure out which invoices belong to which patient. Here is the important parts of my structure.
Invoices Table
InvoiceNumber | DateInvoice | DueDate | StudyID | TypeInvoice
Patients Table
FirstName | LastName | PatientID
InvoiceFields
id | InvoiceNumber | PatientID |
I need make a query that lists the invoice table data based upon a PatientID. Below is the query that I attempted, but got no where with. Thank you for your time.
SELECT Distinct
invoicefields.InvoiceNumber,
invoices.DateInvoice
FROM `invoices`, `patients`, `invoicefields`
WHERE invoicefields.PatientID = patients.PatientID
and invoicefields.InvoiceNumber = invoicefields.InvoiceNumber
GROUP BY invoicefields.InvoiceNumber

SELECT InvT.InvoiceNumber, InvT.DateInvoice
FROM InvoiceTable InvT
INNER JOIN InvoiceFields InvF ON InvF.InvoiceNumber = InvT.InvoiceNumber AND InvF.PatientID = #PatientID
So pretty much since you only need data from the InvoiceTable and you indicate you have the PatientID. I propose you just join to the Cross Reference table InvoiceFields and use the PatientID column in that query to filter it down to what you need. I had a more complex example using an exist before I realized you didn't need anything from Patients.
You could use this if you need information on the Patient as well (Just put the needed columns in the Select)
SELECT InvT.InvoiceNumber, InvT.DateInvoice
FROM InvoiceTable InvT
INNER JOIN InvoiceFields InvF ON InvF.InvoiceNumber = InvT.InvoiceNumber AND InvF.PatientID = #PatientID
INNER JOIN Patient Pat ON Pat.PatientID = InvF.PatientID
You can put the #PatientID portion on the join for either Patient or InvoiceFields. There really shouldn't be a performance difference between either way if you indexes are right.
The Response to the Below Comment but where I can show it cleaner:
SELECT IT.InvoiceNumber
,IT.DateInvoice
FROM InvoiceTable InvT
WHERE EXISTS (SELECT InvF.PatientID
FROM InvoiceFields InvF
WHERE InvF.InvoiceNumber = InvT.InvoiceNumber
AND InvF.PatientID = #PatientID)
This will return all the rows for the patient from InvoiceTable and if InvoiceNumber is Unique will not have any duplicates. Though this way you only have access to InvoiceTable to return Data from. If you only want one put a TOP 1 on it:
SELECT TOP 1 IT.InvoiceNumber
,IT.DateInvoice
FROM InvoiceTable InvT
WHERE EXISTS (SELECT InvF.PatientID
FROM InvoiceFields InvF
WHERE InvF.InvoiceNumber = InvT.InvoiceNumber
AND InvF.PatientID = #PatientID)

SELECT * from invoices i
inner join invoicefields iFld
on i.invoiceNumber = iFld.invoiceNumber
inner join patients p
on iFld.patientID = p.patientID
and p.patientID = 1235125
This should get you started in the right direction at least. I'm not sure what columns you wanted to return and/or if there's any nulls in the tables. Nulls will affect which rows are returned

Related

Multiple joins on same table

I'm trying to achieve a query which seems simple but I can't make it work correctly. Here's my database tables structures:
members
-> id
-> last_name
-> first_name
activities
-> id
registrations
-> id
-> member_id
tandems
-> id
-> activitie_id
-> registration_member_one
-> registration_member_two
Here's what i want to achieve:
Mutliple members can register to an activity. Then, i group the registrations by tandems. I want a view with all the tandems listed and there's my problem. When I try a query, it gives me multiple rows, duplicated many times.
Below, an example of the table I want to have:
tandems.id | activities.id | registration_member_one.members.last_name | registration_member_two.members.last_name
1 | 3 | John Doe | Jane Doe
Here's the query I'm working on:
SELECT
tandems.*,
memberOne.id, memberOne.last_name, memberOne.first_name,
memberTwo.id, memberTwo.last_name, memberTwo.first_name,
memberOne_registration.member_id as memberOne,
memberTwo_registration.member_id as memberTwo
FROM tandems
JOIN registrations as memberOne_registration
ON memberOne_registration.member_id = tandems.registration_member_one
JOIN members as memberOne ON memberOne.id = memberOne_registration.member_id
JOIN registrations as memberTwo_registration
ON memberTwo_registration.member_id = tandems.registration_member_two
JOIN members as memberTwo ON memberTwo.id = memberTwo_registration.member_id
WHERE activitie_id = 3;
Any help appreciated!
The error is caused by joining wrong column (member_id) of registrations table with tandems table, instead column registrations.id should be used.
SELECT
tandems.*,
memberOne.id, memberOne.last_name, memberOne.first_name,
memberTwo.id, memberTwo.last_name, memberTwo.first_name,
memberOne_registration.id as memberOne,
memberTwo_registration.id as memberTwo
FROM tandems
JOIN registrations as memberOne_registration ON memberOne_registration.id = tandems.registration_member_one
JOIN members as memberOne ON memberOne.id = memberOne_registration.member_id
JOIN registrations as memberTwo_registration ON memberTwo_registration.id = tandems.registration_member_two
JOIN members as memberTwo ON memberTwo.id = memberTwo_registration.member_id
WHERE activitie_id = 3;
Although other query is virtually the same, I hate working with unnecessarily long alias names so worked with "r1" and "r2" for the two instances of the registration table, and "m1" and "m2" for the members joining context.
SELECT
t.id,
t.activitie_id,
m1.last_name LastName1,
m1.first_name FirstName1,
m2.last_name LastName2,
m2.first_name FirstName2
FROM
tandems t
LEFT join registrations r1
ON t.registration_member_one = r1.id
LEFT JOIN members m1
ON r1.member_id = m1.id
LEFT join registrations r2
ON t.registration_member_two = m2.id
LEFT JOIN members m2
ON r2.member_id = m2.id
WHERE
t.activitie_id = 3;
To help you on this and in the future... Although mentally done, I try to mentally draw out how do I get the pieces together from the first table downstream. This can be seen too by the visual indentation almost like a tree view extension from T to R1 to M1, then R2 to M2 is a different branch. I also prefer to list the left table/alias.column = right table/alias.column in the join condition. How does T get to R1, then how does R1 get to M1.
In this, I used LEFT JOIN to each respective registration and member -- just-in-case only one person registered and a second may be pending. Not sure how your registration is actually structured.

GROUP_CONCAT within CONCAT

Database hierarchical structure is as follow
Student Name List of fee Assigned to Each
Student
List of Scholarship Assigned to Each Fee
As structure, expected output is
Student Name-Fee->Scholarship1, Scholarship2
Karan-1.Annual Fee->Economic Scholarship,Incapable Scholarship,2.Monthly Fee
But what I am getting
Student Name-Fee->Scholarship1, Student Name-Fee->Scholarship2
Karan-1.Annual Fee->Economic Scholarship,1.Annual Fee->Incapable Scholarship,2.Monthly Fee
What is wrong in here ? Though I am nesting CONCAT, but not getting expected output
CONCAT(student.en_ttl,'-',GROUP_CONCAT(DISTINCT fee.id,'.',fee.en_ttl,
COALESCE(CONCAT('->',sch.en_ttl),''))) AS fee
SQL Fiddle
You basically need to two levels of GROUP BY. So, we will need to use a Derived Table here. First subquery will aggregate at the level of fee; and then the second level would aggregate those fee details at the level of student.
Also, in newer (and ANSI SQL compliant) versions of MySQL, you need to ensure that any non-aggregated column in the SELECT clause should be in the GROUP BY clause as well.
Query
SELECT
CONCAT(stud_ttl,'-',GROUP_CONCAT(CONCAT(fee_det, COALESCE(CONCAT('->',fee_sch), '')))) AS fee
FROM
(
SELECT student.ttl AS stud_ttl,
CONCAT(fee.id,'.',fee.ttl) AS fee_det,
Group_concat(DISTINCT sch.ttl) AS fee_sch
FROM inv_id
JOIN student
ON student.id = inv_id.std
JOIN inv_lst
ON inv_lst.ftm = inv_id.ftm
JOIN fee
ON fee.id = inv_lst.fee
JOIN sec_fee
ON sec_fee.fee = fee.id
AND sec_fee.cls = student.cls
AND sec_fee.sec = student.sec
LEFT JOIN std_sch
ON std_sch.std = student.id
LEFT JOIN sec_sch
ON sec_sch.sch = std_sch.sch
AND sec_sch.fee = fee.id
LEFT JOIN sch
ON sch.id = sec_sch.sch
GROUP BY student.ttl, fee_det, fee.ttl
) dt
GROUP BY stud_ttl;
Result
| fee |
| -------------------------------------------------------------------- |
| Karan-1.Annual->Economic Scholarship,Incapable Scholarship,2.Monthly |
View on DB Fiddle

joined query to return data

I have the following query which returns data only if the join exists. How do I return from the last joined table (#__unis) datas, even if there is no relationship between those tables without to write another query?
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
join #__unis AS uni ON uni.id= subject.university
where uni.id = 1
table structure http://sqlfiddle.com/#!2/19add
use LEFT JOIN instead of join
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
right join #__unis AS uni ON uni.id= subject.university
where uni.id = 1
Try this..
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
left join #__unis AS uni ON ( uni.id= subject.university AND uni.id = 1 )

SQL query for matching multiple values in the same column

I have a table in MySQL as follows.
Id Designation Years Employee
1 Soft.Egr 2000-2005 A
2 Soft.Egr 2000-2005 B
3 Soft.Egr 2000-2005 C
4 Sr.Soft.Egr 2005-2010 A
5 Sr.Soft.Egr 2005-2010 B
6 Pro.Mgr 2010-2012 A
I need to get the Employees who worked as Soft.Egr and Sr.Soft.Egr and Pro.Mgr. It is not possible to use IN or Multiple ANDs in the query. How to do this??
One way:
select Employee
from job_history
where Designation in ('Soft.Egr','Sr.Soft.Egr','Pro.Mgr')
group by Employee
having count(distinct Designation) = 3
What you might actually be looking for is relational division, even if your exercise requirements forbid using AND (for whatever reason?). This is tricky, but possible to express correctly in SQL.
Relational division in prosa means: Find those employees who have a record in the employees table for all existing designations. Or in SQL:
SELECT DISTINCT E1.Employee FROM Employees E1
WHERE NOT EXISTS (
SELECT 1 FROM Employees E2
WHERE NOT EXISTS (
SELECT 1 FROM Employees E3
WHERE E3.Employee = E1.Employee
AND E3.Designation = E2.Designation
)
)
To see the above query in action, consider this SQLFiddle
A good resource explaining relational division can be found here:
http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division
If you need to get additional information back about each of the roles (like the dates) then joining back to your original table for each of the additional designations is a possible solution:
SELECT t.Employee, t.Designation, t.Years, t1.Designation, t1.Years, t2.Designation, t2.Years
FROM Table t
INNER JOIN t2 ON (t2.Employee = t.Employee AND t2.Designation = 'Sr.Soft.Egr')
INNER JOIN t3 ON (t3.Employee = t.Employee AND t3.Designation = 'Soft.Egr')
WHERE t.Designation = 'Pro.Mgr';
Why not the following (for postgresql)?
SELECT employee FROM Employees WHERE Designation ='Sr.Soft.Egr'
INTERSECT
SELECT employee FROM Employees WHERE Designation ='Soft.Egr'
INTERSECT
SELECT employee FROM Employees WHERE Designation ='Pro.Mgr'
Link to SQLfiddle
I know this might not optimized, but I find this much much easier to understand and modify.
Try this query:
SELECT DISTINCT t1.employee,
t1.designation
FROM tempEmployees t1, tempEmployees t2, tempEmployees t3
WHERE t1.employee = t2.employee AND
t2.employee = t3.employee AND
t3.employee = t1.employee AND
t1.designation != t2.designation AND
t2.designation != t3.designation AND
t3.designation != t1.designation

I need to finalize this MySQL multiple table JOIN

I have entires, equipments, brands, times and seasons.
entries:
id
time
equipment_1
equipment_2
equipments:
id
id_brand
brands:
id
name
times:
id
id_season
seasons:
id
name
My actual SQL query is:
SELECT entries.*, times.id_season AS id_season
FROM entries, seasons
WHERE entries.time = times.id
But in the final query I need the next information that I don't know how to obtain it:
The name for each entries.equipment_ as equipment_1_name and equipment_2_name which is set in brands.name.
The name of the season as season_name.
Thank you in advance!
Assuming you have normalized data. This avoid costly cartesian joins. I never use cartesian joins myself, although there are some cases where they are useful. Not here, though.
SELECT
entries.*,
times.id_seasons AS id_season,
b1.name AS equipment_1_name,
b2.name AS equipment_2_name,
seasons.name AS season_name
FROM entries
LEFT JOIN equipments AS equipments_1
ON equipments_1.id = entries.equipment_1
LEFT JOIN brands AS brands_1
ON brands_1.id = equipments_1.id_brand
LEFT JOIN equipments AS equipments_2
ON equipments_2.id = entries.equipment_2
LEFT JOIN brands AS brands_2
ON brands_2.id = equipments_2.id_brand
LEFT JOIN times
ON times.id = entries.time
LEFT JOIN seasons
ON seasons.id = times.id_season;