Trying to get mutliple inner joins in my sql - mysql

I'm using xampp with mysql and have been trying to format a query that uses inner joins on 4 seperate tables. The inner join contains the tables customer, bankaccounts, has and transactions. Has links the bank account and customer tables from M:N to 1:M while transactions is linked to bank accounts. I have attempted the following query:
SELECT t.TransactionID,
t.Description,
t.Amount,
t.isLoan,
t.TransactionDate,
a.AccountID,
a.SortCode,
a.Name,
a.CreationDate,
c.FirstName,
c.LastName
c.DateofBirth
FROM transactions AS t
INNER JOIN bankaccounts AS a
#inner join will create a new table by combining the values selected based on if they satisfy the on condition below
ON t.TransactionID IN ( SELECT t.TransactionID
FROM transactions
WHERE t.TransactionDate BETWEEN '2021-11-25' AND '2021-12-01'
)
AND t.AccountID = a.AccountID
INNER JOIN has ON has.AccountID = a.AccountID ---- > #multiple inner joins can occur on multiple tables
INNER JOIN customers AS c ON has.CustomerID = c.CustomerID;
However this currently only gives an error.
What I need is to link together all the tables while ensuring that only transactions between those specific dates are picked.
Is there any way to solve this?

You should move the condition with the subquery to the WHERE clause:
SELECT t.TransactionID, t.Description, t.Amount, t.isLoan, t.TransactionDate,
a.AccountID, a.SortCode, a.Name, a.CreationDate,
c.FirstName, c.LastName, c.DateofBirth
FROM transactions AS t
INNER JOIN bankaccounts AS a ON t.AccountID = a.AccountID
INNER JOIN has ON has.AccountID = a.AccountID
INNER JOIN customers AS c ON has.CustomerID = c.CustomerID
WHERE t.TransactionDate BETWEEN '2021-11-25' AND '2021-12-01';

Related

How to write a SQL query to get sum of transactions?

I want sql query for this . I have three tables customer,account, transaction
the schema of the are as below
I want to get customer details, account id, sum of transaction id
Your query is quite close. Try this:
SELECT c.customer_id, a.Account_id, SUM(t.transaction_amount) as amount
FROM Account a INNER JOIN
Customer c
ON a.customer_id = c.customer_id INNER JOIN
Transaction t
ON a.account_id = t.account_id
GROUP BY c.customer_id, a.account_id;
Note the use of table aliases to simplify the query. And -- more importantly -- the SELECT columns and GROUP BY columns are consistent.
Because the customer_id is in the Account table, you don't need the Customer table. So, you can simplify this to:
SELECT a.customer_id, a.Account_id, SUM(t.transaction_amount) as amount
FROM Account a INNER JOIN
Transaction t
ON a.account_id = t.account_id
GROUP BY a.customer_id, a.account_id;
You can Sum the transactions grouped by CustomerID and then join to the customers table on the CustomerID like this:
SELECT c.Customer_name, c.Customer_mobile, t.Transaction_sum
FROM Customer c
JOIN (
SELECT t.CustomerID, SUM(t.Sum) as Transaction_sum
FROM transactions t
GROUP BY t.CustomerID
) t on t.CustomerID = c.CustomerID

Is it possible to select from the result of a subquery in a join

So I have a large subquery and I would like to join on that subquery while using the result of the subquery in the join.
For example, I have a table called patient and one called appointment, and I would like to get the number of appointments per patient with given criteria.
Right now I am doing something like this:
SELECT
t1.*
FROM
(
SELECT
patient.name,
patient.id,
appointment.date
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
WHERE
/* a **lot** of filters, additional joins, etc*/
) t1
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
GROUP BY
patient.id
) t2 ON t1.id = t2.id
The problem is that this returns the number of appointments for each patient independent from the subquery above it. I tried writing the join as this:
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
t1
GROUP BY
patient.id
)
But obviously I'm getting an error saying that table t1 doesn't exist. Is there any way for me to do this cleanly without having to repeat all of the filters from t1 in t2?
Thanks!
Why not use window functions?
SELECT p.name, p.id, a.date,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_appointments
FROM patient p LEFT JOIN
appointment a
ON a.patient_id = p.id
WHERE . . .
This provides the count based on the WHERE filtering. If you wanted a count of all appointments, then do the calculation before applying the WHERE:
SELECT p.name, p.id, a.date,
COALESCE(a.cnt, 0) as num_total_appointments,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_matching appointments
FROM patient p LEFT JOIN
(SELECT a.*,
COUNT(*) OVER (PARTITION BY a.patient_id) as cnt
FROM appointment a
) a
ON a.patient_id = p.id
WHERE . . .

using same where clause on multiple tables before joining them

Is there a better way of joining two tables and using same where clause on both of them? I am doing it as follows:
SELECT a.account_id,
a.account,
b.tax,
b.rate
FROM (SELECT account_id,
account
FROM accounts
WHERE account_id IN (SELECT account_id
FROM account_location
WHERE location = "A")) AS a
LEFT JOIN (SELECT tax,
rate
FROM tax
WHERE tax_id IN (SELECT tax_id
FROM account_tax
WHERE account_id IN (SELECT account_id
FROM account_location
WHERE location = "A"))) AS b
ON a.account_id = b.account_id
I have 4 tables. Accounts, account_location which has list of accounts mapped to locations, tax which has all taxes, account_tax which has mapping of all taxes applicable to each account. The code works fine, but can this be made faster?
If I'm not mistaking, this query should do the same:
select
a.account_id, a.account, t.tax, t.rate
from
accounts a
inner join account_location al
on al.account_id = a.account_id
and al.location = 'A'
left join account_tax at
on at.account_id = a.account_id
left join tax t on t.tax_id = at.tax_id
I think it will be faster do to more efficient joins (MySQL isn't good with subselects, especially in those join conditions. Also, I think it's more readable.
You can used derived tables (and possibly alternatively CTE's) to DRY up what you are doing in the subquery. Then join to the derived table, instead of using IN. You can do this for the other subqueries as well:
Select a.account_id, a.account, b.tax, b.rate
from
(select account_id from account_location where location="A") as UsefulAccounts
inner join
(
select account_id, account from accounts acc
INNER JOIN UsefulAccounts ua on acc.account_id = ua.account_id
) as a
left join
(
select tax, rate
from tax t
inner join account_tax actx
on t.account_id = acc.account_id
inner join UseFulAccounts ua on actx.account_id = actx.account_id
) as b
on a.account_id = b.account_id;

MySQL inner join different results

I am trying to work out why the following two queries return different results:
SELECT DISTINCT i.id, i.date
FROM `tblinvoices` i
INNER JOIN `tblinvoiceitems` it ON it.userid=i.userid
INNER JOIN `tblcustomfieldsvalues` cf ON it.relid=cf.relid
WHERE i.`tax` = 0
AND i.`date` BETWEEN '2012-07-01' AND '2012-09-31'
and
SELECT DISTINCT i.id, i.date
FROM `tblinvoices` i
WHERE i.`tax` = 0
AND i.`date` BETWEEN '2012-07-01' AND '2012-09-31'
Obviously the difference is the inner join here, but I don't understand why the one with the inner join is returning less results than the one without it, I would have thought since I didn't do any cross table references they should return the same results.
The final query I am working towards is
SELECT DISTINCT i.id, i.date
FROM `tblinvoices` i
INNER JOIN `tblinvoiceitems` it ON it.userid=i.userid
INNER JOIN `tblcustomfieldsvalues` cf ON it.relid=cf.relid
WHERE cf.`fieldid` =5
AND cf.`value`
REGEXP '[A-Za-z]'
AND i.`tax` = 0
AND i.`date` BETWEEN '2012-07-01' AND '2012-09-31'
But because of the different results that seem incorrect when I add the inner join (it removes some results that should be valid) it's not working at present, thanks.
INNER JOIN statement will retrieve rows that are stored in both table of the jion statement.
Try a LEFT JOIN statement. This will return rows that are in first table but not necessary in the second one :
SELECT DISTINCT i.id, i.date
FROM `tblinvoices` i
LEFT JOIN `tblinvoiceitems` it ON it.userid=i.userid
LEFT JOIN `tblcustomfieldsvalues` cf ON it.relid=cf.relid
WHERE i.`tax` = 0
AND i.`date` BETWEEN '2012-07-01' AND '2012-09-31'
INNER JOIN means show only records where the same ID value exists in both tables.
LEFT JOIN means to show all records from left table (i.e. the one that precedes in SQL statement) regardless of the existance of matching records in the right table.
Try LEFT Join instead of INNER JOIN
SELECT DISTINCT i.id, i.date
FROM `tblinvoices` i
LEFT JOIN `tblinvoiceitems` it ON it.userid=i.userid
LEFT JOIN `tblcustomfieldsvalues` cf ON it.relid=cf.relid
WHERE i.`tax` = 0
AND i.`date` BETWEEN '2012-07-01' AND '2012-09-31'

MySQL statement that combines a sub-query and a JOIN is not working

SELECT i.id AS id, i.modify_date as modify_date, s.subscription as subscriptionid, p.paid/i.total AS paidratio
FROM invoices i,
(SELECT p.invoice, sum(amount) AS paid FROM payments p GROUP BY p.invoice) p
LEFT JOIN sub_to_inv s
ON i.id=s.invoice
WHERE p.invoice=i.id
AND i.corporation='3'
AND i.payer=1
The error I get is "unknown column on i.id" which is total bogus - invoices (i) has an id row for sure. They all do.
The purpose of the sub=query is to find out how much of the invoice has been paid. For an invoice that has a "total" column of 1000.00, for example, could have 2 or 3 split payments. What I ultimately wnat to do here is list all the unpaid invoices or partially invoices first. But before I even get to the ORDER BY stage, I need to figure out this error.
Use JOIN syntax for all joins. Don't mix JOIN syntax with the comma-style SQL-89 syntax.
SELECT ...
FROM invoices i
INNER JOIN (SELECT...) p
ON p.invoice=i.id
LEFT OUTER JOIN sub_to_inv s
ON i.id=s.invoice
WHERE
AND i.corporation='3'
AND i.payer=1
Explanation: JOIN has higher precedence than comma-joins. So p JOIN s is evaluated before the query evaluates the join to i. Therefore, in the clause ON i.id=s.invoice, the i table is not yet known and is an invalid reference.
See http://dev.mysql.com/doc/refman/5.1/en/join.html, in the doc following "Join Processing Changes in MySQL 5.0.12".
Can you try this ?
SELECT i.id AS id, i.modify_date as modify_date, s.subscription as subscriptionid, p.paid/i.total AS paidratio
FROM invoices i
LEFT JOIN
(SELECT p.invoice, sum(amount) AS paid FROM payments p GROUP BY p.invoice) p
ON p.invoice=i.id
LEFT JOIN sub_to_inv s
ON i.id=s.invoice
WHERE i.corporation='3'
AND i.payer=1
I think you might be running into issues because of the order of your table joins in your SQL. Have you tried using an inner join. Perhaps try:
SELECT
i.id AS id,
i.modify_date as modify_date,
s.subscription as subscriptionid,
p.paid/i.total AS paidratio
FROM
invoices i
INNER JOIN
(SELECT
p.invoice,
sum(amount) AS paid
FROM
payments p
GROUP BY
p.invoice) p
ON
p.invoice=i.id
LEFT JOIN
sub_to_inv s
ON
i.id=s.invoice
WHERE
i.corporation='3' AND i.payer=1