I have three tables with same structure.
table1
id | email | count
1 | test1#abc.com | 5
2 | test2#abc.com | 5
3 | test3#abc.com | 5
table2
id | email | count
1 | test1#abc.com | 50
2 | test1#abc.com | 50
3 | test3#abc.com | 50
table3
id | email | count
1 | test1#abc.com | 40
2 | test1#abc.com | 45
3 | test1#abc.com | 50
Now what i want is for table1, for first record "test1#abc.com", I need sum of "count" field of next two tables. So i used below query
SELECT (IFNULL(sum(distinct(table2.count)), 0) +
IFNULL(sum(distinct(table3.count)), 0)) as total
FROM table1
LEFT JOIN table2 ON table1.email = table2.email
LEFT JOIN table3 ON table1.email = table3.email
WHERE table1.email = 'test1#abc.com'
This query gives me below record:
185
But the result should be as below:
235
This is because i have used distinct when adding field. But if i don't use distinct, it gives me 285.
Please help. What should i do?
Your issue is because, first, you're using LEFT JOIN (no sense with summation since NULL-records will provide nothing), second, that's how JOIN works. Illustrate with query:
SELECT
t1.id AS id_1,
t1.email AS email_1,
t1.count AS count_1,
t2.id AS id_2,
t2.email AS email_2,
t2.count AS count_2,
t3.id AS id_3,
t3.email AS email_3,
t3.count AS count_3
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.email=t2.email
INNER JOIN table3 AS t3 ON t1.email=t3.email
WHERE
t1.email='test1#abc.com'
(fiddle is here). As you can see, you'll get repeated id's from second and third tables - and - yes, that's because there are multiple rows for joining condition.
To resolve your issue you may add distinction by id into join (and later filtering that with variables or like that), but I would not recommend it. JOIN is simply not the thing for your issue. Use UNION, like:
SELECT
SUM(`count`) AS s
FROM
(
SELECT
table2.count
FROM
table2
WHERE
email='test1#abc.com'
UNION ALL
SELECT
table3.count
FROM
table3
WHERE
email='test1#abc.com'
) AS u
(see the fiddle)
Related
Example Table Structure
Table 1
ID | Name | Price
-----------------------------
1 | Casio | 30
2 | Titan | 40
Table 2
ID | Place | Price
-----------------------------
1 | Cali | 30
2 | Mexi | 10
Operation to perform:
Table1(Price) - Table2(Price) for ID = 1
New Table 1
ID | Name | Price
-----------------------------
1 | Casio | 0
2 | Titan | 40
ID matches in both tables
You should consider another database design to handle this case.
But to answer your question, you can create a view :
create view Differences2 as (
select t1.id, t1.price - t2.price
from t1, t2
where t1.id = t2.id
)
As you told both table will have same ID column you can use following query.
SELECT table1.ID, table1.Name, (table1.Price-table2.Price) AS Price
FROM table1
INNER JOIN table2 ON table1.ID = table2.ID
If you want to update record you can use following:
UPDATE table1
INNER JOIN table2 ON table1.ID = table2.ID
SET table1.Price = (table1.Price-table2.Price)
I'm working on a tricky query and just don't understand how to approach it since neither JOIN gives me desirable result.
I have two tables:
Table1:
id
value
Tabel2:
id
table1_id
parameter (1,0)
value
I need to select everything from Table_1, but if there is a row in Table2 with table1_id = table1.id and parameter = 1, I want to include table2.value in the outcome. Note, that there can be multiple rows with table1_id = table1.id in Table2, but only one with parameter=1.
So, what I'm looking to get as a a result
table1.id | table1.value | table2.parameter |table2.value
1 | v1 | |
2 | v1 | 1 | v2
3 | v1 | |
4 | v1 | 1 | v2
Can someone help me with a query. Thank you for your time.
SELECT *
FROM
Table1 LEFT JOIN Table2
ON (Table1.id = Table2.table1_id AND Table2.parameter = 1)
;
You can use left join and case when for showing the table2 value
select
t1.id,
t1.value,
t2.parameter,
case when t2.table_id is not null and t2.parameter = 1 then t2.value else null end as table2_value
from table1 t1
left join table2 t2 on t2.table1_id = t1.id
I'm using the following query to select data from 3 different tables. tbl_invoices and tbl_clients have unique records. Each tbl_invoices record has multiple tbl_invoice_entries records:
$query = 'SELECT T1.*, T2.*, T3.*
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients T3
ON T1.client = T3.client_id
WHERE date_format(date, '%Y') = ".$_POST['year']." AND date_format(date, '%c') = ".$_POST['month']." ORDER BY date, number ASC'
$stmt = $conn->prepare($query)
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
This currently returns all records in tbl_invoice_entries. How do I change my query in order to only return the first tbl_invoice_entries record for each tbl_invoices record.
Here are the tables:
tbl_clients
+----+-----------+----------+
| id | firstname | lastname |
+----+-----------+----------+
| 1 | John | Doe |
| 2 | Jane | Doe |
+----+-----------+----------+
tbl_invoices
+----+--------+--------+------------+
| id | number | client | date |
+----+--------+--------+------------+
| 1 | 14 | 1 | 2015-07-14 |
| 1 | 15 | 2 | 2015-07-14 |
+----+--------+--------+------------+
tbl_invoice_entries
+----+----------------+------------+
| id | invoice_number | produkt |
+----+----------------+------------+
| 1 | 14 | Fish |
| 2 | 14 | Bread |
| 3 | 15 | Vegetables |
| 4 | 15 | Fruit |
+----+----------------+------------+
So the results I'm looking for are:
John Doe 14 Fish 2015-07-14
Jane Doe 15 Vegetables 2015-07-14
Thanks for any help!
By linking the invoice_entries table not directly through the invoice number but by the id of its first entry you can achieve what you want:
SELECT firstname,lastname,number,product,date
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T2.id =(select min(id) from tbl_invoice_entries
where invoice_number=number)
LEFT JOIN tbl_clients T3
ON T1.client = T3.id
WHERE ...
You need to tell the RDBMS what you intend by the first row. There is no natural order in tuples. If you want the tuple with lowest ID given the same invoice_number, then it would require another query
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN ( SELECT MIN(id) AS id, invoice_number FROM tbl_invoice_entries
GROUP BY invoice_number ) AS tbl2
USING (id);
The above query is equivalent to tbl_invoice_entries but only has the lowest ID of each invoice number. You can do it as a VIEW (actually two, since you can't use subqueries in a VIEW):
CREATE VIEW tbl_invoice_entries_firstnumber AS
SELECT MIN(id) AS id, invoice_number
FROM tbl_invoice_entries
GROUP BY invoice_number;
CREATE VIEW tbl_invoice_entries_first AS
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN tbl_invoice_entries_firstnumber
USING (id);
After that you can use tbl_invoice_entries_first instead of tbl_invoice_entries in your current query.
Keep in mind that the view is dynamic, so it is only a shorthand for a more complex query. This means that your current query will become more complicated and require a longer time:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries_first AS T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id; -- you have no client_id in T3
I have set up a fiddle here.
Or you can modify your query more, and add a JOIN condition on T2 so that it only fetches, again, the minimum ID - or whatever ordering condition you prefer:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries AS T2
ON (
-- (( T1.number = T2.invoice_number AND )) --
T2.id = (
SELECT MIN(id) FROM tbl_invoice_entries
WHERE invoice_number = number
))
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id;
UPDATE: The check on number was commented out (see also #cars10's solution) because it is carried over by the inner subquery.
Finally you can do this in code, i.e. you save the value of the previous tuple and order the query as needed; then discard all unneeded tuples. If you have few entries per invoice, this might be worthwhile:
// pseudo code
if (prev.client == tuple.client)
and
(prev.invoice == tuple.invoice)
continue;
prev = tuple;
-- use tuple.
I'm trying to write JOIN Query with 3 Tables. I need Query to Return Total SUM of each users based Link Value Passed to Query. Added below the Table Structure, required result and Query that i tried.
Table 1: UserDetails
| ID | Name | Link |
| 1 | User A | 12 |
| 2 | User B | 12 |
| 3 | User C | 12 |
Table 2: Saving
|CreatedBy| Amount |
| 3 | 100 |
| 3 | 50 |
| 2 | 75 |
Table 3: Expense
|CreatedBy| Amount |
| 2 | 20 |
| 1 | 15 |
| 3 | 85 |
By Passing Link Value to Query must return Total(savings+expense) for each user.
Result 1: If Passing Link Value 12.
Query Result be
|User Name| Total |
|User A | 15 |
|User C | 235 |
Result 2: If Passing Link Value 11.
Query Result be
|User Name| Total |
|User B | 95 |
Below query Not returning any result.
SELECT
t1.name,
SUM(t2.total_amount+t3.total_amount)
FROM
userdetails t1
LEFT JOIN savings t2
ON t2.created_by=t1.id
LEFT JOIN expense t3
ON t3.created_by=t1.id
WHERE
t1.link=12
AND t1.status=1
AND t2.status=2
AND t3.status=2
GROUP BY
t2.created_by,
t3.created_by
When you make an outer join you cannot place conditions in the where clause otherwise it nullifies the outer join and turns it into a normal inner join. You can however get what you want (based on your where clause) by adding the condition into the join like this:
SELECT
t1.name,
SUM(t2.total_amount+t3.total_amount)
FROM
userdetails t1
LEFT JOIN savings t2
ON t2.created_by=t1.id
AND t2.status=2
LEFT JOIN expense t3
ON t3.created_by=t1.id
AND t3.status=2
WHERE
t1.link=12
AND t1.status=1
GROUP BY
t2.created_by,
t3.created_by
You also don't normally want to group by fields you aren't naming in your select clause:
SELECT
t1.name,
SUM(t2.total_amount+t3.total_amount)
FROM
userdetails t1
LEFT JOIN savings t2
ON t2.created_by=t1.id
AND t2.status=2
LEFT JOIN expense t3
ON t3.created_by=t1.id
AND t3.status=2
WHERE
t1.link=12
AND t1.status=1
GROUP BY
t1.name
select
u.Name,
u.link,
c.total
from user_details u,
(select
"created by",
sum(amount) Total
from
(select
"created by",
amount
from expense
union all
select
"created by",
amount
from savings)
group by "created by") c
where u.ID=c."created by"
and u.link=12;
Try this:
SELECT A.Name,A.link,B.total
FROM user_details A,
(SELECT 'created by', SUM(amount) AS Total
FROM
(SELECT 'created by',amount
FROM expense
UNION ALL
SELECT'created by',amount
FROM savings)
GROUP BY 'created by') B
WHERE A.ID=B.'created by'
AND A.link=12;
You can use field_name as 'Field Name' or 'Column Title' to display it in the results.
Make sure you have a column created by in the table.
I'm going to make this a little clearer as I've realised it's not as clear as it should be.
Table One
ID, COMPANY_ID, OPPORTUNITY, DATE_CREATE
Table Two
ID,ASSIGNED_BY_ID
What I am trying to do is add all the values in OPPORTUNITY for each ASSIGNED_ID. COMPANY_ID in table one is the same as ID in table two.
So for example:
Table One
COMPANY_ID | OPPORTUNITY | DATE_CREATE
1000 | 50 | 2013/09/19
1000 | 100 | 2013/09/18
1000 | 200 | 2013/09/18
1005 | 100 | 2013/09/18
1005 | 200 | 2013/09/18
Table Two
ID | ASSIGNED_BY_ID
1000 | 4
1000 | 4
1000 | 4
1005 | 2
1005 | 2
So I want a SELECT statement that will provide these results:
ASSIGNED_BY_ID | OPPORTUNITY
4 | 350
2 | 300
I would like individual select statements per ASSIGNED_BY_ID.
How is this possible?
Try this.
SELECT t1.ID,SUM(OPPORTUNITY) AS total
FROM table1 t1
INNER JOIN table2 t2 ON t1.COMPANY_ID=t2.ID
WHERE t1.DATE_CREATE BETWEEN '$fromdate' AND '$todate' AND t2.ASSIGNED_BY_ID=1
GROUP BY t1.ID
UPDATE
SELECT t2.ASSIGNED_BY_ID,SUM(OPPORTUNITY) AS total
FROM table1 t1
INNER JOIN table2 t2 ON t1.COMPANY_ID=t2.ID
WHERE t1.DATE_CREATE BETWEEN '$fromdate' AND '$todate'
GROUP BY t2.ASSIGNED_BY_ID
Use this please
SELECT SUM(a.OPPORTUNITY) AS total, a.ID FROM table1 a inner join table2 b on a.COMPANY_ID = b.ID WHERE a.DATE_CREATE BETWEEN '$fromdate' AND '$todate' AND b.ASSIGNED_BY_ID=1 group by a.ID;