How to subtract values of two different columns from two different tables? - php

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)

Related

MYSQL slow query when getting total rows from another table using while loop

I am new to mysql and I am attempting to get all ID from another table where ID is equal to ID from table 1 and another conditions.
Table 1
+---------------+
| ID model line |
+---------------+
| 1 XX C1 |
| 2 AA C3 |
| 3 SS C1 |
+---------------+
Table 2 ( So if my query is ID = 1 AND model = XX GROUP BY line the total rows from table 2 will return 3 since ID 1,4 and 5 is true.
+----------------------------+
| ID InspectionID model line |
+----------------------------+
| 1 1 XX C1 |
| 2 1 AA C3 |
| 3 1 SS C1 |
| 4 1 XX C2 |
| 5 1 XX C4 |
+----------------------------+
So far i have this query inside a PHP while loop it return what i wanted but the query is really slow.
$query = "SELECT * FROM table2 WHERE inspectionID = '$ID' AND model = '$modelID' GROUP BY line
So i think the best way is to join table1 and table2 and add a column total
sadly my knowledge on mysql and joining table is limited, any suggestions is appreciated.
my target is to create below.
+---------------------+
| ID model line total |
+---------------------+
| 1 XX C1 3 |
| 2 AA C3 0 |
| 3 SS C1 0 |
+---------------------+
Pretty simple join and aggregation. working demo
(note demo includes both answers so far and results.)
We left join so we keep all records from table 1 and join to table 2 to get records matching from table 1. We set the limit on model on the join itself so the filtering is applied to the table2 before the join occurs. thus the count will only include model XX and all other counts for models will be zero.
SELECT T1.ID, T1.Model, T1.Line, count(T2.ID)
FROM table1 T1
LEFT JOIN Table2 T2
on T1.Model = T2.Model
and T2.Model = 'XX'
GROUP BY T1.ID, T1.Model, T1.Line
ORDER BY T1.ID
Just create an SQL View:
CREATE VIEW TABLE_1_2_VIEW AS
SELECT A.id, A.model, A.line, B.inspectionID, COUNT(B.ID) Total
FROM table_1 A LEFT JOIN table_2 B
ON A.model=B.model
GROUP BY A.id, A.model, A.line, B.inspectionID
ORDER BY A.id, A.model, A.line;
You can query the data from this view as if it were a table.
SELECT id, model, line, IF(model='XX', Total, 0) Total
FROM TABLE_1_2_VIEW
WHERE inspectionID=1;
Just that the data in this view would not be updatable.

How to delete a row in a mysql db with inner / left join only if there is no NULL value

I've got one table which looks like this:
id_1 | col_1 | col_2
1 | 450 | 2018-01-30 21:38:00
2 | 111 | 2018-01-30 22:18:00
3 | 222 | 2018-01-31 22:18:00
and the second table looks like this:
id_2 | id_1 | beginn | outdated
1 | 1 | 2018-01-30 11:38:00 | 0
2 | 1 | 2018-01-30 12:18:00 | 1 <===== THIS ROW IS OUTDATED
3 | 1 | 2018-01-30 13:38:00 | 0
4 | 2 | 2018-01-30 14:18:00 | 0
5 | 3 | 2018-01-30 15:38:00 | 1 <===== THIS ROW IS OUTDATED
6 | 2 | 2018-01-30 16:18:00 | 0
How can I delete the values from table1 and table2 (with one single query) only if there will not be any valid join. e.g. delete from table1 the row with id_1=3 and from table2 the row with id_2=5 but NOT the row in table1 with id_1=1 because there are still entries in table2 which can be joined with.
I tried the following, but it will not work:
DELETE a,b FROM table1 a
LEFT JOIN table2 b on a.id_1=b.id_1
WHERE b.outdated=1
AND NOT EXISTS (
SELECT c.id_1 from table1 c
INNER JOIN table2 d on c.id_1=d.id_1
WHERE d.outdated=0)
How can I change my query or which FASTER query can be choosen for my intention
I'm not sure there's a way to do this in one query. This comes close:
DELETE a, b
FROM Table1 AS a
LEFT JOIN Table2 AS b ON a.id_1 = b.id_1
LEFT JOIN Table2 AS c ON a.id_1 = c.id_1 AND c.outdated = 0
WHERE c.id_1 IS NULL
AND (b.id_1 IS NULL -- no match
OR b.outdated = 1)
but it doesn't delete id_2 = 2 from Table2.
I think it may need to be done in two queries: First delete all rows in Table1 that don't join with any outdated = 0 rows in Table2, then delete all the outdated rows in Table2.
DELETE a
FROM Table1 AS a
LEFT JOIN Table2 AS b ON a.id_1 = b.id_1 AND b.outdated = 0
WHERE b.id_1 IS NULL;
DELETE FROM Table2
WHERE outdated = 1;
Or you can reverse the order, then you don't need to check b.outdated at all:
DELETE FROM Table2
WHERE outdated = 1;
DELETE a
FROM Table1 AS a
LEFT JOIN Table2 AS b ON a.id_1 = b.id_1
WHERE b.id_1 IS NULL;

Mysql IN query instead of multiple AND conditon

I have three mysql tables, category,students and student_category. for each student there is 1 or more category will be there and it is stored in student_category as follows.
1) Categgory
----------------------------
id | category_name
---------------------------
1 | A
2 | B
3 | C
4 | D
2) Students
--------------------------
id | name
--------------------------
1 | John
2 | Kumar
3 | Ashok
4 | Jorge
5 | Suku
-------------------------
2) student_category
-----------------------------------------
id | student_id | category_id
-----------------------------------------
1 | 1 | 2
2 | 1 | 4
3 | 2 | 3
4 | 2 | 1
5 | 3 | 2
------------------------------------------
I need to select students which contain category_id 2 and 4.
i used query as follows but it return either students contain category 2 or category 4.
select A.name from students A, student_category B where A.id=B.student_id
and B.category_id IN (2,4)
Try this query:
SELECT t1.id,
t3.name
FROM students t1
INNER JOIN student_category t2
ON t1.id = t2.student_id
INNER JOIN students t3
ON t1.id = t3.id
WHERE t2.category_id IN (2, 4)
GROUP BY t1.id
HAVING COUNT(DISTINCT t2.category_id) = 2
Explanation:
This query joins together the students and student_category tables, and then removes all records which are not category 2 or 4. This means that each student would then only have category 2 and 4 records associated with him. The HAVING clause then restricts further by requiring that a student have two distinct categories, which if true must mean that the student has both category 2 and 4.
Demo here:
SQLFiddle
try this :
select name from Students where id in (select student_id from student_category where category_id in (2,4))
your query is fine btw.
Try this one:
select
s.name
from
Students s,
Categgory c,
student_category sc
where
sc.student_id = s.id
and sc.category_id = c.id
and c.id = 2
and c.id = 4
You can check it on SQL Fiddle.
Have to take distinct student name as it will repeat if a student falls in more than one category.

SQL SELECT only rows having MAX value of a column from two different tables

My two table setup is like below:
table1
+------+---------+--------------------------------------+
| id | tail | content |
+------+---------+--------------------------------------+
| 1 | abc | ... |
| 2 | def | ... |
| 3 | ghi | ... |
| 4 | def | ... |
| 5 | jkl | ... |
+------+-------+----------------------------------------+
table2
+------+--------+---------------------------------------+
| id | tailID | value | others |
+------+--------+---------------------------------------+
| 1 | 2 | 412 | |
| 2 | 3 | 215 | |
| 1 | 2 | 571 | |
| 1 | 4 | 123 | |
+------+--------+---------------------------------------+
I like to get all columns from this two tables in a row with matched tail = tailID but not duplicate rows which has same tail.
For the duplicate TAIL, just need to get the single row of max VALUE of same tail.
I am currently using
SELECT table1.tail, table2.other_column
FROM table1
INNER JOIN table2
on table1.id = table2.tailID
WHERE table1.some_coloum = "a sepecific string"
ORDER BY table2.value
But it returns many duplicates of same tail.
I just need to have single row for duplicate TAIL with hightes VALUE of table2.
DISTINCT with CROSS APPLY:
SELECT DISTINCT t1.tail,
t2.other_column,
t3.[value]
FROM table1 t1
CROSS APPLY (
SELECT tailid,
MAX([value]) as [value]
FROM table2
WHERE tailid = t1.id
GROUP BY tailid
) as t3
INNER JOIN table2 t2
ON t2.tailid = t3.tailid AND t3.[value] = t2.[value]
WHERE t1.some_coloum = "a sepecific string"
First group table2 then join
SELECT table1.tail, table2.other_column
FROM table1
INNER JOIN (
SELECT tailID, max(value) as value
FROM table2
GROUP BY tailID
) t2g ON t2g.tailID = table1.ID
INNER JOIN table2
on t2g.tailID = table2.tailID AND t2g.value = table2.value
WHERE table1.some_coloum = "a sepecific string"
ORDER BY table2.value
The query still may return multiple rows for a table1 row if there are 2 or more rows in table2 with the same max(value) and tailID.
Selected only rows where is MAX value of column value
SELECT table1.tail, MAX(table2.value)
FROM
table1
INNER JOIN table2 ON table1.id = table2.tailID
WHERE table1.content = "test"
http://sqlfiddle.com/#!9/b70d29/3/0

Insert Comma Separated values through MySQL query

I have one table (in phpmyadmin) with the following fields and structure:
Table 1
id | sponsor
1 | -1
2 | 1
3 | 1
4 | 2
5 | 4
6 | 4
Now i want to insert data from above table into new table as below:
Table 2
id | children
1 | 2,3
2 | 4
3 |
4 | 5,6
5 |
6 |
Actually this is Tree structure, which i have saved in mysql database.
I have already written a script in php but as there are more then 100K rows in table 1 so its taking too much time. Please tell me an efficient sql query to do this task quickly.
Query:
SQLFIDDLE Example
SELECT
t1.id,
(SELECT group_concat(id separator ', ')
FROM table1 t2
WHERE t2.sponsor = t1.id) AS children
FROM table1 t1
GROUP BY t1.id
Result:
| ID | CHILDREN |
-----------------
| 1 | 2, 3 |
| 2 | 4 |
| 3 | (null) |
| 4 | 5, 6 |
| 5 | (null) |
| 6 | (null) |
Insert Statement:
INSERT INTO table2
SELECT
t1.id,
(SELECT group_concat(id separator ', ')
FROM table1 t2
WHERE t2.sponsor = t1.id) AS children
FROM table1 t1
GROUP BY t1.id
This is similar to #Justin's answer but uses a left join instead of a correlated subquery:
INSERT INTO Table2 (id, children)
SELECT
sp.id,
GROUP_CONCAT(ch.id) AS children
FROM Table1 sp
LEFT JOIN Table1 ch ON sp.id = ch.sponsor
GROUP BY t1.id
;
A demonstration of the SELECT statement's result can be found (and played with) at SQL Fiddle (the schema having been borrowed from Justin).
One of your SELECT elements should be a GROUP_CONCAT(...) as column, which will concatenate those values separated with commas. If you want to filter by one of those values, you can use GROUP BY -whatever- HAVING find_in_set( -number- , column )
See if the following helps
INSERT INTO table2
SELECT sponsor, GROUP_CONCAT(id)
FROM table1
GROUP BY id

Categories