We have 4 tables:
mysql> desc Products;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| product_id | int(11) | NO | PRI | NULL | auto_increment |
| product | varchar(30) | NO | | NULL | |
+------------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> desc Vendors;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| vendor_id | int(11) | NO | PRI | NULL | auto_increment |
| vendor | varchar(30) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> desc Prices;
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| price_id | int(11) | NO | PRI | NULL | auto_increment |
| vendor_id | int(11) | NO | MUL | NULL | |
| product_id | int(11) | NO | MUL | NULL | |
| price | double | YES | | NULL | |
+------------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> desc Bought;
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| bought_id | int(11) | NO | PRI | NULL | auto_increment |
| product_id | int(11) | NO | MUL | NULL | |
| date | date | YES | | NULL | |
| pieces | int(11) | YES | | 1 | |
+------------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
now we need some complex select statements, to get the tables we need:
first table need columns [vendor, product, price, vendors(that offers the product)].
second table should show what was bought between $date1 and $date2 [product, pieces, vendor, price, date]
last table should show what could've been saved in the given time [vendor(the cheapest vendor for the product), product, pcs, price(for one product), sum(price for n products)].
As this wouldnt be complicated enaugh, the resulting tables have to show the names, instead of a key. We were sitting on this the hole day, but none of us have the knowledge to perform needed searches, so any help would be greatly appreciated.
Look into joins for selecting data from multiple tables:
SELECT * FROM Prices LEFT JOIN (Vendors, Products)
ON (Products.product_id=Prices.product_id AND Vendors.vendor_id=Prices.vendor_id)
Related
Query #1:
SELECT SUM(size)
FROM RepoSize s
LEFT JOIN VirtualRepo v ON s.repo_id = v.repo_id
WHERE v.repo_id IS NULL;
+----------------+
| SUM(size) |
+----------------+
| 61550890457198 |
+----------------+
1 row in set (0.32 sec)
Query #2:
SELECT SUM(size)
FROM RepoSize
WHERE repo_id NOT IN (SELECT repo_id FROM VirtualRepo);
+----------------+
| SUM(size) |
+----------------+
| 61551148262106 |
+----------------+
1 row in set (0.45 sec)
I thought the 2 SQL queries would return the same result, but the truth is the second value is larger than the first, repo_id is the primary key in both tables.
table structure:
mysql> desc RepoSize;
+---------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------------+------+-----+---------+-------+
| repo_id | char(37) | NO | PRI | NULL | |
| size | bigint(20) unsigned | YES | | NULL | |
| head_id | char(41) | YES | | NULL | |
+---------+---------------------+------+-----+---------+-------+
mysql> desc VirtualRepo;
+-------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+-------+
| repo_id | char(36) | NO | PRI | NULL | |
| origin_repo | char(36) | YES | MUL | NULL | |
| path | text | YES | | NULL | |
| base_commit | char(40) | YES | | NULL | |
+-------------+----------+------+-----+---------+-------+
As repo_id is primary key in both the tables, there is not a possibility of difference because of nulls in the field. So ideally both the queries should give the same result unless the data has changed in between the execution. So most probably the difference is because of change in data in between.
So I'm struggling with this very (very) basic MySQL query which is supposed to retrieve courrier records ordered by number of joined reactions.
I have this table:
mysql> describe courrier;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| envoi | datetime | NO | | NULL | |
| intro | longtext | NO | | NULL | |
| courrier | longtext | NO | | NULL | |
| slug | varchar(255) | NO | | NULL | |
| categorie_id | int(11) | YES | MUL | NULL | |
| reponse | longtext | YES | | NULL | |
| recu | datetime | YES | | NULL | |
| published | tinyint(1) | NO | | NULL | |
| image_id | int(11) | YES | UNI | NULL | |
| like_count | int(11) | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
12 rows in set (0.02 sec)
Which has:
mysql> select count(id) from courrier;
+-----------+
| count(id) |
+-----------+
| 56 |
+-----------+
1 row in set (0.00 sec)
Joined with:
mysql> describe reaction;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| courrier_id | int(11) | YES | MUL | NULL | |
| date | datetime | NO | | NULL | |
| ip | varchar(15) | NO | | NULL | |
| reaction | longtext | NO | | NULL | |
| url | varchar(255) | YES | | NULL | |
| name | varchar(255) | NO | | NULL | |
| status | int(11) | NO | | NULL | |
| email | varchar(255) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
9 rows in set (0.01 sec)
Which has:
mysql> select count(id) from reaction;
+-----------+
| count(id) |
+-----------+
| 236 |
+-----------+
1 row in set (0.00 sec)
On: ALTER TABLE reaction ADD CONSTRAINT FK_5DA165A18BF41DC7 FOREIGN KEY (courrier_id) REFERENCES courrier (id);
(backticks removed for readability)
So when I run this query:
SELECT c0_.id AS id_0,
c0_.name AS name_1,
c0_.slug AS slug_2,
c0_.envoi AS envoi_3,
c0_.intro AS intro_4,
c0_.courrier AS courrier_5,
c0_.reponse AS reponse_6,
c0_.published AS published_7,
c0_.like_count AS like_count_8,
c0_.recu AS recu_9,
COUNT(r1_.id) AS sclr_10,
c0_.image_id AS image_id_11,
c0_.categorie_id AS categorie_id_12
FROM courrier c0_
INNER JOIN reaction r1_ ON c0_.id = r1_.courrier_id
ORDER BY sclr_10 DESC LIMIT 25
I'm quite naturally expecting to be provided with one row per record in courrier along with a additional column specifying the number of joined reaction records.
But I'm returned: 1 row in set (0.03 sec). It's the first record inserted in courrier and the additional column is filled with the number 242.
What did I do wrong?
You should use a group by clause, otherwise the count will aggregate the whole result set:
SELECT c0_.id AS id_0 /*, ...*/,
COUNT(r1_.id) AS sclr_10
FROM courrier c0_
INNER JOIN reaction r1_ ON c0_.id = r1_.courrier_id
GROUP BY c0_.id
ORDER BY sclr_10 DESC
LIMIT 25
Note: if you are also interested in courrier records that have no corresponding record in reaction (count = 0), then use LEFT JOIN instead of INNER JOIN.
I need to make a join across 4 tables whilst picking the maximum (i.e. most recent) timestamp of test to associate with a person. For each student in a class, I want to lookup what their most recent test is, and get its ID and timestamp
SELECT students.ref,
students.fname,
students.sname,
classes.name AS 'group',
tests.id,
max(tests.timestamp)
FROM tests, students, classlinks, classes
WHERE tests.ref=students.ref AND
classlinks.ref=students.ref AND
classlinks.classid=29 AND
tests.grade=2 AND
tests.subject=2
GROUP BY students.ref
ORDER BY students.sname ASC, students.fname ASC
looks like it is perfect: for each student in a class, it gives the timestamp of their most recent test. Unfortunately, the test ID associated with that timestamp is wrong: it is just giving the test ID of a random test.
If I change the 'group by' to be
GROUP BY students.ref, tests.id
then the query matches correct test IDs to correct timestamps, but now there are several entries for each student. Does anyone have any advice so that I can get one row for each student, with correct test ID matched to correct most recent timestamp? Any help appreciated. Thanks.
Table descriptions:
mysql> describe students;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| ref | varchar(50) | NO | UNI | NULL | |
| fname | varchar(22) | NO | | NULL | |
| sname | varchar(22) | NO | | NULL | |
| school | int(11) | NO | | NULL | |
| year | int(11) | NO | | NULL | |
+--------+-------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
mysql> describe classes;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subject | int(11) | YES | MUL | NULL | |
| type | int(11) | YES | | 1 | |
| school | int(11) | YES | | NULL | |
| year | int(11) | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
mysql> describe classlinks;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| ref | varchar(50) | YES | MUL | NULL | |
| subject | int(11) | YES | | NULL | |
| school | int(11) | YES | | NULL | |
| classid | int(11) | YES | MUL | NULL | |
| type | int(11) | YES | | 1 | |
+---------+-------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
mysql> describe tests;
+------------+-------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subject | int(11) | YES | | NULL | |
| ref | varchar(22) | NO | MUL | NULL | |
| test | int(3) | NO | | NULL | |
| grade | varchar(22) | NO | | NULL | |
| timestamp | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| lastupdate | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
I am assuming that the combination of (ref,timestamp) is unique in tests table. Here is my solution but I don't have any of your sample data to verify it. If it is incorrect than post a sample data so that I can test it.
UPDATE
Here is the update query which is working check the sqlfiddle
SELECT students.ref,
students.fname,
students.sname,
classes.name AS 'group',
tests.id,
T.timestamp
FROM (select ref,max(timestamp) as timestamp from tests group by ref)as T
natural join tests, students, classlinks, classes
WHERE
T.ref=students.ref AND
classlinks.ref=students.ref AND
classlinks.classid=classes.id AND
classlinks.classid=29 AND
tests.grade=2 AND
tests.subject=2
ORDER BY students.sname ASC, students.fname ASC
Using the logic in SQL the query can be written as follows, not sure about mySQL but hope the logic works.
Select ref
,fname
,sname
,ID
,group
,Timestamp
From
(select
S.ref
,S.fname
,S.sname,
,T.id
,classes.name AS 'group'
,T.timestamp
from
tests T,students S, classlinks, classes
Where
T.ref=S.ref and
T.grade=2 AND
classlinks.ref=students.ref AND
classlinks.classid=29 AND
classlinks.classid=classes.id AND
T.subject=2 ) A
inner join
(SELECT tests.ref
,max(tests.timestamp)
FROM
tests
group by
tests.ref
) B
on
A.ref=b.ref and
A.timestamp = b.timestamp
I have succesfully created a database in mySQL using the commandline and imported some data. It currently looks like this..
desc data;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| code | varchar(10) | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
SELECT * FROM data;
+----+----------+
| id | code |
+----+----------+
| 1 | 123abc
| 2 | 234def
| 3 | 567ghi
| 4 | 890jkl
I would like to add a column to the table called timestamp, I am doing this with..
alter table data add timestamp VARCHAR(20);
But then my table looks like this...
desc data;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| code | varchar(10) | YES | | NULL | |
| timestamp | varchar(20) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
SELECT * FROM data;
+----+----------+-----------+
| id | code | timestamp |
+----+----------+-----------+
| NULL |
| NULL |
| NULL |
| NULL |
Where am I going wrong?
here you can see the backticks
alter table `data` add `timestamp` VARCHAR(20);
SAMPLE
MariaDB []> desc data;
+-------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| e | enum('x1','x2','x3') | YES | | NULL | |
+-------+----------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
MariaDB []> alter table `data` add `timestamp` VARCHAR(20);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB []> desc data;
+-----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| e | enum('x1','x2','x3') | YES | | NULL | |
| timestamp | varchar(20) | YES | | NULL | |
+-----------+----------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
Table Data
MariaDB [who]> select * from `data`;
+----+------+-----------+
| id | e | timestamp |
+----+------+-----------+
| 1 | x1 | NULL |
| 2 | x2 | NULL |
+----+------+-----------+
2 rows in set (0.00 sec)
MariaDB [who]>
This question already has answers here:
Return row only if value doesn't exist
(2 answers)
Closed 7 years ago.
The foreign key trade.ticker_id point to ticker.id.
I want to find all rows in 'ticker' that have zero rows in 'trades' linked to it.
mysql> describe trade;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| time | datetime | NO | | NULL | |
| price | float | NO | | NULL | |
| quantity | int(11) | NO | | NULL | |
| source | varchar(64) | YES | | NULL | |
| buyer | varchar(64) | YES | | NULL | |
| seller | varchar(64) | YES | | NULL | |
| initiator | varchar(64) | YES | | NULL | |
| ticker_id | int(11) | YES | MUL | NULL | |
+-----------+-------------+------+-----+---------+----------------+
9 rows in set (0,00 sec)
mysql> describe ticker;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(64) | NO | | NULL | |
| long_name | varchar(250) | YES | | NULL | |
| exchange_id | int(11) | YES | MUL | NULL | |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0,00 sec)
Try this:
SELECT * FROM ticker WHERE id NOT IN (SELECT ticker_id FROM trade)
You can use left join and is null or in other words anti join
select tc.* from ticker tc
left join trade tr on tr.ticker_id = tc.id
where tr.ticker_id is null