I need to get all IDs from table A where all the Expiry date from Table B (INNER JOIN ID = A_ID) are < today (2018-06-29) but i'm not sure and a bit confusing for the query.
Based on my example (2018-06-29) i need to retrieve only Name-4 because ALL Expiry date from Table B are < 2018-06-29
Table A
ID | Name |
-------------
1 | Name-1
2 | Name-2
3 | Name-3
4 | Name-4
5 | Name-5
6 | Name-6
7 | Name-7
Table B
ID | A_ID | Expiry
-----------------------
1 | 1 | 2018-06-29
2 | 2 | 2018-07-29
3 | 2 | 2018-06-29
4 | 3 | 2018-07-29
5 | 3 | 2018-04-29
6 | 4 | 2018-05-29
7 | 4 | 2018-04-29
8 | 6 | 2018-09-29
9 | 6 | 2018-10-29
You are correct that you need both the GROUP BY and the HAVING clauses. Since you require that all expiry dates for a matching A_ID are less than a given date, you must check the MAX() expiry for that grouping.
SELECT ta.* FROM tableA ta JOIN tableB tb ON ta.ID = tb.A_ID
GROUP BY ta.id
HAVING MAX(Expiry) < '2018-06-20';
DEMO
Related
I wanted to UPDATE the value of my below table (row & col_md) :
Current Data
| id | id_cat | row | col_md |
| --- | ------ | ---- | ------ |
| 1 | 1 | 1 | 4 |
| 2 | 1 | 2 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 3 |
| 5 | 2 | 2 | 4 |
| 6 | 2 | 2 | 4 |
| 7 | 3 | 1 | 12 |
| 8 | 3 | 1 | 12 |
| 9 | 3 | 2 | 3 |
That may look something like the below table. (I want to have the same content of rows that id_cat=1 have, in rows with id_cat=2 & 3).
Required Data:
| id | id_cat | row | col_md |
| --- | ------ | ---- | ------ |
| 1 | 1 | 1 | 4 |
| 2 | 1 | 2 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 4 |
| 5 | 2 | 2 | 5 |
| 6 | 2 | 3 | 5 |
| 7 | 3 | 1 | 4 |
| 8 | 3 | 2 | 5 |
| 9 | 3 | 3 | 5 |
id_cat 2 and 3 should have the same "row" and "col_md" values as in id_cat=1.
I've tried with this post first answer like this:
UPDATE `myTable` AS t1 JOIN `myTable` AS t2 ON t2.id_cat=1
SET t1.row = t2.row, t1.col_md = t2.col_md
WHERE t1.id_cat = 2 or t1.id_cat=3;
but that results on all "row" column values equal to 1.
What I'm doing wrong and what's the way to do this right?
EDIT:
The tables above are just examples to make this ask easier to understand, but the real table is bigger (4k rows) and:
"row" column with id_cat=1 can have any number and not a sequence as in the example.
"col_md" columns can have any number too.
That's why the update must set a copy of the id_cat=1 "row" and "col_md" values in the id_cat!=1 "row" and "col_md" values.
If this can't be done with just MySQL, a php script will be nice too.
In the example query you gave, you are updating t1.row with t2.row. As you are joining on the id_cat, this will result in multiple rows selected to update a single row, so the outcome just takes the first row.
What you actually want, is to make the 1-to-1 relation in the update, so what needs to be changed in your query is to add the row matching in the join and remove the assignment in the SET, like this:
UPDATE `myTable` AS t1 JOIN `myTable` AS t2 ON t2.id_cat=1 AND t1.row = t2.row
SET t1.col_md = t2.col_md
WHERE t1.id_cat = 2 or t1.id_cat=3;
Which then gives the output of:
MariaDB [testart]> select * from myTable;
+------+--------+------+--------+
| id | id_cat | row | col_md |
+------+--------+------+--------+
| 1 | 1 | 1 | 4 |
| 2 | 1 | 2 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 4 |
| 5 | 2 | 2 | 5 |
| 6 | 2 | 3 | 5 |
| 7 | 3 | 1 | 4 |
| 8 | 3 | 1 | 4 |
| 9 | 3 | 2 | 5 |
+------+--------+------+--------+
9 rows in set (0.00 sec)
Currently able to achieve the SQL query for your desired result.
SELECT t2.id_cat, t1.row, t1.col_md
FROM (SELECT row, col_md from mytable WHERE id_cat=1) as t1 , mytable as t2
GROUP BY t2.id_cat, t1.row, t1.col_md
The above will return the following..
I suggest to use INSERT statement along with the above query to put the record into a new table and drop the old one.
Cheers!
EDITED...
Instead of Updating table, alternate approach could be to Insert the required record into a new table.
This can be achieved with following four steps
Create a tmp table with same fileds (id Auto_Increment, id_cat, row, col_md)
Insert to tmp table with this statement...
INSERT INTO tmp(id_cat, row, col_md)
SELECT t2.id_cat, t1.row, t1.col_md
FROM (SELECT row, col_md from mytable WHERE id_cat=1) as t1 , mytable as t2
GROUP BY t2.id_cat, t1.row, t1.col_md
Remove/Rename 'myTable'.
Rename 'tmp' table to 'myTable'.
Hope this will serve the purpose...
Cheers!
it's not enough to tell which group you want the data from, you need to match id to id.
in your case t2.id 4 and 7 to t1.id 1, t2.id 5 and 8 to t1.id 2, and t2.id 6 and 9 to t1.id 3.
SELECT #d := COUNT(*) FROM myTable WHERE id_cat = 1;
UPDATE `myTable` AS t1
JOIN `myTable` AS t2 ON t2.id_cat=1 AND
t2.id = IFNULL(NULLIF(t1.id MOD #d, 0), #d)
SET t1.row = t2.row, t1.col_md = t2.col_md
WHERE t1.id_cat = 2 or t1.id_cat=3;
#d holds the number of lines where id_cat = 1
we divide t1.id by #d and match the remainder (MOD) to t2.id.
when t1.id is multiple of #d the remainder is 0 and we have to match it to #d
so we make 0 into NULL and NULL into #d
In my understanding, the difficult part about this question is to relate each record to update (ie each record with id_cat IN (2, 3)) to the relevant original record (record with id_cat = 1).
Based on your sample data, I understand that you expect series of records for each id_cat (I can see three groups of three records, sorted by increasing id), so I would assume that you want to relate each record to the original that has the same sequence in the group of record where id_cat = 1.
Assuming MySQL 8.0, a typical approach to assign a number to a record within a group is ROW_NUMBER(). Consider this simple query:
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY id_cat ORDER BY id) rn
FROM t
Yields:
| id | id_cat | rw | col_md | rn |
| --- | ------ | --- | ------ | --- |
| 1 | 1 | 1 | 4 | 1 |
| 2 | 1 | 2 | 5 | 2 |
| 3 | 1 | 3 | 5 | 3 |
| 4 | 2 | 1 | 3 | 1 |
| 5 | 2 | 2 | 4 | 2 |
| 6 | 2 | 2 | 4 | 3 |
| 7 | 3 | 1 | 12 | 1 |
| 8 | 3 | 1 | 12 | 2 |
| 9 | 3 | 2 | 3 | 3 |
Now with this set-up in mind, we can turn this query to a Common Table Expression (available also starting MySQL 8.0), and JOIN it as need with the original table to do the UPDATE:
WITH cte AS (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY id_cat ORDER BY id) rn
FROM t
)
UPDATE t t0
INNER JOIN cte t1 ON t1.id = t0.id
INNER JOIN cte t2 ON t2.id_cat = 1 AND t2.rn = t1.rn
SET t0.rw = t2.rw, t0.col_md = t2.col_md
WHERE t0.id_cat IN (2, 3)
Details:
t0 is the original table, where records having id_cat IN (2, 3) need to be updated
t1 is the corresponding record in the CTE (to which a row number was assigned)
t2 is the record in the CTE that has id_cat = 1 and the same row number as the record being updated
Demo on DB Fiddle:
| id | id_cat | rw | col_md |
| --- | ------ | --- | ------ |
| 1 | 1 | 1 | 4 |
| 2 | 1 | 2 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 4 |
| 5 | 2 | 2 | 5 |
| 6 | 2 | 3 | 5 |
| 7 | 3 | 1 | 4 |
| 8 | 3 | 2 | 5 |
| 9 | 3 | 3 | 5 |
I'm trying to add a new page onto an old site, a records page that'd show which players won the most money or won the race when they were a certain age
The user table looks like this
***********************************
| id | name | age | bday |
| 1 | bob | 15 | 2000-07-30 |
| 2 | john | 14 | 2001-07-30 |
| 3 | mary | 13 | 2002-07-30 |
***********************************
the race_results table looks like this
************************************************************
| id | raceid | userid | place | winnings | date |
| 1 | 1 | 1 | 1 | 1000 | 2006-04-10 |
| 2 | 1 | 2 | 5 | 50 | 2005-02-15 |
| 3 | 1 | 3 | 6 | 50 | 2010-06-12 |
| 4 | 2 | 1 | 1 | 1000 | 2009-05-29 |
| 5 | 2 | 2 | 3 | 250 | 2003-01-12 |
************************************************************
What's the most practical approach to a query that'd calculate the year range when Bob was 3 years old and match that with the race results table to see how many times he won 1st place within that particular date range?
SELECT COUNT(*)
FROM 'race_results'
INNER JOIN 'user' on user.id = race_results.userid
WHERE user.name = 'bob'
AND race_results.place = 1
AND race_results.date >= ADDDATE(user.bday, INTERVAL 3 YEAR)
AND race_results.date < ADDDATE(user.bday, INTERVAL 4 YEAR);
To get a list of all 3 yr old 1st placers and how many times they won, not just for 'bob' ...
SELECT user.name, COUNT(*)
FROM 'race_results'
INNER JOIN 'user' on user.id = race_results.userid
WHERE race_results.place = 1
AND race_results.date >= ADDDATE(user.bday, INTERVAL 3 YEAR)
AND race_results.date < ADDDATE(user.bday, INTERVAL 4 YEAR)
GROUP BY user.name;
I have this 2 table in database in sql
TABLE1:
USER id | state| TYPE | time |
1 | 1 | 1 | time |
2 | 1 | 2 | time |
3 | 1 | 2 | time |
4 | 1 | 2 | time |
5 | 0 | 1 | time |
6 | 0 | 1 | time |
TABLE2:
id |USER id| run
1 | 3 | 7
2 | 1 | 5
3 | 1 | 5
4 | 4 | 8
5 | 2 | 6
6 | 2 | 6
7 | 3 | 7
8 | 3 | 7
9 | 3 | 7
10 | 3 | 7
11 | 2 | 6
12 | 4 | 8
13 | 4 | 8
14 | 1 | 5
15 | 2 | 6
16 | 2 | 6
17 | 5 | 9
18 | 4 | 8
I am printing this
SELECT * FROM TABLE1 WHERE state != 0
it will print row this way
USER ID 1
USER ID 2
USER ID 3
USER ID 4
But I want to ascending this by count
WHERE, Count = num of row of TABLE2
Where user id=1 or 2 or..N
Here:
count of USER id 1 = 3
count of USER id 2 = 5
count of USER id 3 = 5
count of USER id 4 = 4
Now i want to ascending
Table 1 where high count to low count from table 2 and high run to low run
USER ID 3
USER ID 2
USER ID 4
USER ID 1
Using PHP AND MYSQLI
Please help me
select t1.id, count(t2.id) as t2_count
from table1 t1
left join table2 t2 on t1.`user id` = t2.`user id`
group by t1.id
order by t2_count desc
I am trying to combine these two tables then order it by one column (stamp), and aliasing the second table's id field. I've tried joins, merges, but nothing seems to work. I am also trying to group them by the mm
Table note
id | mm | stamp |
==========================
1 | 5 | 2009-12-11 |
2 | 33 | 2010-09-10 |
3 | 22 | 2011-07-08 |
4 | 1 | 2012-05-06 |
Table note_admin
id | mm | stamp |
==========================
1 | 5 | 2009-08-15 |
2 | 5 | 2011-11-11 |
3 | 5 | 2012-01-08 |
4 | 35 | 2012-02-06 |
Query I thought would work:
(SELECT * FROM note WHERE mm=5)
UNION
(SELECT id AS a_id, mm, stamp FROM note_admin WHERE mm=5)
ORDER BY stamp DESC
Expected Result
id | a_id | mm | stamp |
================================
| 3 | 5 | 2012-01-08 |
| 2 | 5 | 2011-11-11 |
1 | | 5 | 2009-12-11 |
| 1 | 5 | 2009-08-15 |
I don't even know if this is possible. I found a way to sort this in PHP but it would be much easier if it can be done in mySQL. Thanks.
I think you mean this, note the same 4 column names (not sure about the order by though):
(SELECT a_id as NULL, note.* FROM note WHERE mm=5) UNION (SELECT id AS a_id, NULL as id, mm, stamp FROM note_admin WHERE mm=5) ORDER BY stamp DESC
ok, first of all sorry for the title, but I could not work out a better one :(
This is the problem:
I have two tables, properties and properties_rooms, linked each other by the propery ID.
properties table:
+---------------+------------+
| id_properties | pr_title |
+---------------+------------+
| 1 | test |
| 2 | dummy |
+---------------+------------+
properties_rooms table:
+---------------+-------------------+--------------+----------+
| id_prop_rooms | pro_id_properties | pro_id_rooms | pro_size |
+---------------+-------------------+--------------+----------+
| 1 | 1 | 4 | 5.00 |
| 2 | 1 | 18 | 17.00 |
| 3 | 2 | 6 | 12.00 |
| 4 | 2 | 24 | 11.00 |
| 5 | 1 | 4 | 10.00 |
| 6 | 1 | 6 | 10.00 |
| 7 | 1 | 6 | 12.00 |
+---------------+-------------------+--------------+----------+
I'm working on an advanced search, where users can search for a property that has more than a rooms of the same type (ie two bedrooms, 3 bathrooms and so on).
Sadly, I find myself stuck on this, since I can't "filter" the same dataset with multiple clause; if i have to filter only one there will be no problems, since I can use an HAVING clause.
I worked out this select:
SELECT id_properties, pro_id_rooms, COUNT(*) as total,
IF ((pro_id_rooms = 4 AND COUNT(*) >= 2) OR (pro_id_rooms = 6 AND COUNT(*) >= 2), 1, 0) as flag
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties, pro_id_rooms
ORDER BY id_properties
Inside the IN clause there are the properties that I know they have at least one of requested rooms. They came from a previous query since I have to work with GROUP BY and HAVING.
The IF part inside the select is built at run-time, since I get the information from the request.
This is the result:
+---------------+--------------+-------+------+
| id_properties | pro_id_rooms | total | flag |
+---------------+--------------+-------+------+
| 1 | 4 | 2 | 1 |
| 1 | 6 | 2 | 1 |
| 1 | 18 | 1 | 0 |
| 2 | 6 | 1 | 0 |
| 2 | 24 | 1 | 0 |
+---------------+--------------+-------+------+
I think it could work, I only need to add an HAVING flag > 0 and I'm done.
My question is, is there anything better?
Tables aren't very large: properties one could be something like 1k, rooms one about 10k.
I'm afraid that if the user puts too much rooms, the query would become an enormous IF statement...
SELECT id_properties, SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties
HAVING bedrooms >= 3 AND bathrooms >= 2
Changes
SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
For each checkbox the user has selected, you need a SUM(pro_id_rooms = x) AS nrofx in your WHERE.
HAVING bedrooms >= 3 AND bathrooms >= 2
This is where you check the number of a particular room.