MySQL: Sub-query troubles - mysql

So I am attempting my very first sub query and ran into a small problem... Why is the query not taking into account my WHERE clause?
My query:
SELECT *
FROM Product
WHERE stdUnitPrice < 5*
(SELECT MIN(stdUnitPrice)
FROM Product
WHERE discontinued = 'A')
But in the results I am still getting values in the discontinued column that are NOT just 'A'
Here are the results:
# productId, prodName, stdUnitPrice, qtyPerUnit, discontinued
3, Aniseed Syrup, 11.00, 12 - 550 ml bottles, A
13, Konbu, 6.60, 2 kg box, A
19, Teatime Chocolate Biscuits, 10.12, 10 boxes x 12 pieces, A
21, Sir Rodney's Scones, 11.00, 24 pkgs. x 4 pieces, A
23, Tunnbrod, 9.90, 12 - 250 g pkgs., A
**24, Guarana Fantastica, 4.95, 12 - 355 ml cans, D**
33, Geitost, 2.75, 500 g, A
41, Jack's New England Clam Chowder, 10.61, 12 - 12 oz cans, A
45, Rogede sild, 10.45, 1k pkg., A
46, Spegesild, 13.20, 4 - 450 g glasses, A
47, Zaanse koeken, 10.45, 10 - 4 oz boxes, A
52, Filo Mix, 7.70, 16 - 2 kg boxes, A
54, Tourtiere, 8.19, 16 pies, A
74, Longlife Tofu, 11.00, 5 kg pkg., A
75, Rhonbrau Klosterbier, 8.52, 24 - 0.5 l bottles, A
78, Bob's Down Home Juice, 7.90, 6 pack, A

Try this:
select *
from Product
where stdUnitPrice < (5 * (select min(stdUnitPrice) from Product ) )
and discontinued = 'A'

It appears as though MySQL is looking at the where and thinking stdUnitPrice < 5
As well, your where needs to be on the main query.
Try moving your math into the subquery like so:
SELECT *
FROM Product
WHERE stdUnitPrice <
(SELECT 5*MIN(stdUnitPrice)
FROM Product)
AND discontinued = 'A'

So the reasoning for this not working the way you want it to is because you are missing the where clause in your first query. Let me break it down a little for you.
select * from Product where stdUnitPrice < 5* (select min(stdUnitPrice) from Product where discontinued = 'A')
so in this query the sub query gets executed first so lets assume that we set the sub query to a variable:
var subquery = select min(stdUnitPrice) from Product where discontinued = 'A';
Now after that subquery is executed it is then plugged back into the original query like so: (using the new variable name)
select * from Product where stdUnitPrice < 5 * (subquery);
so to get this to include a where discontinued = 'A' you would need to change your query to the following:
SELECT * FROM Product WHERE stdUnitPrice < 5 * (SELECT MIN(stdUnitPrice) FROM Product WHERE discontinued = 'A') AND discontinued = 'A';
I hope this helps.
EDIT: Just to clarify you can't actually use a variable like that im just using that as an example to show how the query will actually be executed.

You are performing an aggregate subset operation that is filtered, however, your main query will return all rows. You are basically asking to return all rows * the minimum value in the table. You need t return the minimum value within all rows that match your selection clause.

Related

MySQL update multiple rows using arrays

How can we update multiple rows at once in case of below stated data
studentId = [1,2,5,7,9]
marks = [25, 22, 27, 30, 24]
what will be the MySQL statement, if we want to update studentId 1 with 25 marks, studentId 2 with 22 marks, studentId5 with 27 marks and so on.
Please note: Have to update in 1 query only.
Thanks in advance :)
If you are using MySql 8.0+ you can create a CTE that returns the rows of the ids that you want to update and their marks and join it to the table:
WITH cte(studentId, marks) AS (VALUES
ROW(1, 25), ROW(2, 22), ROW(5, 27), ROW(7, 30), ROW(9, 24)
)
UPDATE tablename t
INNER JOIN cte c ON c.studentId = t.studentId
SET t.marks = c.marks
See the demo.
For previous versions, instead of the CTE you can join a query that uses UNION ALL:
UPDATE tablename t
INNER JOIN (
SELECT 1 studentId, 25 marks UNION ALL
SELECT 2, 22 UNION ALL
SELECT 5, 27 UNION ALL
SELECT 7, 30 UNION ALL
SELECT 9, 24
) c ON c.studentId = t.studentId
SET t.marks = c.marks
See the demo.
You could run one simple query five times, with different values:
UPDATE MyTable SET marks = ? WHERE studentId = ?
The idea is that you would write a loop in some application code, so you process the first element from each of your arrays. Then the second element of both arrays, and so on. For example in PHP:
$studentId = [1,2,5,7,9];
$marks = [25, 22, 27, 30, 24];
$stmt = $pdo->prepare("UPDATE MyTable SET marks = ? WHERE studentId = ?");
for ($i=0; $i<5; ++$i) {
$stmt->execute([$marks[$i], $studentId[$i]]);
}
From its earliest versions, SQL was always intended to be used in combination with an application language. Other languages have variables and loops and conditions and functions, which complement SQL. The easiest solution is to use these languages together.
If you really want to write a single UPDATE statement to update all five, it's possible, but it's really not as clear.
UPDATE MyTable
SET marks = CASE studentId
WHEN 1 THEN 25
WHEN 2 THEN 22
WHEN 5 THEN 27
WHEN 7 THEN 30
WHEN 9 THEN 24
END
WHERE studentId IN (1,2,5,7,9);
There are other clever ways of doing it in one statement, but all these solutions are hard to modify or maintain. They are needlessly complex.
I recommend doing it the simple way.

SQL : I want to compare 10 consecutive value

I am trying to solve a problem with SQL.
I have a SQL database which has a table named "data", in this table you have a row named "points". There is like 10000 float values in this row.
I want to make a desktop application that can compare 10 consecutive values ( which i manually enter ) to his nearest 10 consecutive values in the database.
exemple :
i want to compare this list of 10 values ( that i enter ):
10.1 , 25.4, 2, 35, 45, 78.9, 41.1, 44, 1, 65
to the best list of 10 values in my database where the 10 values are the nearest to my 10 entered values ( IMPORTANT : VALUES HAVE TO BE CONSECUTIVE ).
You can see below what i want to do, i want to get the list of the 10 consecutive values that is the nearest to the 10 values i want to compare.
points ( 10000 values... )
points row : 10, 15.5, 14.3, 2, 1, 10.2, 55, 65.3, 41, 10, 25.2, 3, 34, 44, 78.8, 41.2, 41, 2, 66, 44, 25.1, 33.2, 45, 75, 98, 12, 11.2 etc etc
The 10 values in bold are the best nearest consecutive values:
10 is near to 10.1
25.2 is near to 25.4
3 is near to 2
34 is near to 35
44 is near to 45
78.8 is near to 78.9
41.2 is near to 41.1
41 is near to 44
2 is near to 1
66 is near to 65
Is there any way to do this with SQL Command ?
Thanks in advance.
One option uses a row-limiting correlated subquery:
select v.val,
(select val from mytable t order by abs(t.val - v.val) limit 1) as match_val
from (
select 10.1 as val
union all select 25.4
union all ...
) v
Basically the subquery executes for each row in the from clause (which is where you put the list of values): it scans the table, orders rows by the difference with the original value, and brings the value of top row only.
SQL tables represent unordered sets. You need a column to specify the ordering.
You can use lag() or lead() to bring 10 values together. Then you need a definition of closest. One possibility is to take the absolute value of the differences and add them up:
select t.*
from (select t.*,
lead(val, 1) over (order by <ordercol>) as val_2,
lead(val, 2) over (order by <ordercol>) as val_3,
. . .
lead(val, 9) over (order by <ordercol>) as val_10
from t
) t
order by abs(val - $val_1) + abs(val_2 - $val_2) + . . .
limit 1;
The $val_1, $val_2, and so on represent the values that you are passing in.
The rest is just sorting and taking a limit.

mySql query with HAVING COUNT(DISTINCT) with AND and OR (inclusive and exclusive clause)

I have to modify a mySql custom query inside a Wordpress site.
I will try to explain you my issue, simplifing the query to that is really needed to know.
The table cms_posts (alias 'p') is INNER JOINED to the cms_term_relationship table (alias 'term_rel').
I neet to find all cms_posts with a term_rel.term_taxonomy value included IN 211,210,10,9.
My current query is:
SELECT SQL_CALC_FOUND_ROWS
p.id
FROM cms_posts p
INNER JOIN cms_term_relationships term_rel
ON term_rel.object_id = p.id
WHERE
term_rel.term_taxonomy_id IN (211,210,10,9)
GROUP BY p.id
HAVING
COUNT(DISTINCT term_rel.term_taxonomy_id) = 4
LIMIT 0, 50
The COUNT(DISTINCT ensures that all the relationships i ask in the WHERE clause are striclty followed.
It all works flawless.
But i need to modify the query!
I need to split the WHERE clause. I try to make an example.
I need to take all posts with term_taxonomy in 211 AND 210 but also in 10 OR 9.
I search for all these combinations of posts:
211, 210, 10
211, 210, 9
So i need that 211 and 210 are both needed, but only 1 occurrence of 10 OR 9 are needed too.
Verbosely, i need that my posts are in X, Y, Z categories and at least in A, B or C categories. X, Y, Z categories are exlusive; A, B, C are inclusive.
The question is not so easy to be explained, and my horrible english don't help.
I hope that someone understand my english and even my issue :D
A having clause with count distinct is still a valid approach. What you could do, for example, is use a case expression to treat IDs 9 and 10 the same, thus allowing you to continue counting the distinct number IDs you need. E.g.:
SELECT SQL_CALC_FOUND_ROWS
p.id
FROM vf_posts p
INNER JOIN vf_term_relationships term_rel
ON term_rel.object_id = p.id
WHERE
term_rel.term_taxonomy_id IN (211,210,10,9)
GROUP BY p.id
HAVING
COUNT(DISTINCT CASE term_rel.term_taxonomy_id
WHEN 9 THEN 10
ELSE term_rel.term_taxonomy_id
END) = 4 -- Here!
LIMIT 0, 50
Thanks Mureinik for the answer, but if i try to implement your code, using a case expression it seems doesn't work. If i well understand your aim, with that CASE all the 'inclusive terms', but the first one, are not been considered by the COUNT(DISTINCT. I probably did not implement in the right way your code, but the results was not good enough.
But perhaps i have a solution.
Let me try to give you a better explaination:
- exclusive_terms.term_taxonomy_id is the field to search into;
- there is a list of exclusive values for exclusive_terms.term_taxonomy_id
- and there is also a list of inclusive values for exclusive_terms.term_taxonomy_id
If the user make a search for 211, 210, 9, 217, 215, 218, 10 values of exclusive_terms.term_taxonomy_id, what i need to do first is to separate the exclusive from the inclusive ones.
I obtain 2 lists:
- exclusives 211, 210
- inclusives 9, 217, 215, 218, 10
After that i can compose this query, with 2 JOINS on the same field but calling the resulting field with 2 different aliases, and then makeing a COUNT(DISTINCT only on the exclusive terms.
SELECT SQL_CALC_FOUND_ROWS p.id,
FROM cms_posts p
INNER JOIN cms_term_relationships exclusive_terms ON exclusive_terms.object_id = p.id
INNER JOIN cms_term_relationships inclusive_terms ON inclusive_terms.object_id = p.id
WHERE
exclusive_terms.term_taxonomy_id IN (211, 210)
AND
inclusive_terms.term_taxonomy_id IN (9, 217, 215, 218, 10)
GROUP BY p.id
HAVING
COUNT(DISTINCT exclusive_terms.term_taxonomy_id) = 2
LIMIT 0, 50
It seems to work!

PHP order by clause with array as order by statement

I got a array with a query
This array is ordered by criteria.
Now I want to make a new query
Sample
$array = (987, 2661, 12, 789, 54);
And I want in this order by array selecting articles
select * from article a.number WHERE (a.number IN ($array))
How can I realize that this result is ordered by $array ids?
Thx you 4 answer guys :)
edit :
Article Table:
id, name etc..
Property Table:
id, article_id, name, value
1, 10, journey_days, 2
2, 30, journey_days, 1
3, 40, journey_days, 5
1, 10, stars, 2
2, 10, stars, 4
3, 10, stars, 0
4, 10, stars, 1
I join both tables, but as you can see the property have more then one value per column for one article.
I need to join the Property table to the article table and get all Values there are related from property table to the article, if I make a where clause I just get stars or journey_days.
How can I realise this? to select all property.name values with a where or on clause?
Hope you guys understand my question
Use implode:
$s = implode(",", $array);
$q = "select * from article a.number WHERE (a.number IN ($s))";
You could construct a CASE expression and order by that, but it's probably better to do this in PHP, outside of the database.
... ORDER BY CASE a.number
WHEN 987 THEN 1
WHEN 2661 THEN 2
WHEN 12 THEN 3
WHEN 789 THEN 4
WHEN 54 THEN 5
END;
Or you could use the FIND_IN_SET function:
.... ORDER BY FIND_IN_SET(a.number, "987,2661,12,789,54");

Unable to apply WHERE/AND on MySQL table with 2 columns on MAMP

I thought I had a very simple query to perform, but I can't seem to make it work.
I have this table with 2 columns:
version_id trim_id
1 15
1 25
1 28
1 30
1 35
2 12
2 25
2 33
2 48
3 11
3 25
3 30
3 32
I am trying to get any version-id's that have say a sub-set of trim_id's. Let's say all version_id's that have trim_id's 25 and 30. My obvious attempt was :
SELECT * FROM table WHERE trim_id=25 AND trim_id=30
I was expecting to have version_id 1 and 3 as a result, but instead I get nothing.
I am working with the latest version of MAMP, which has some odd behavior, like in this case it just tells me its 'LOADING' and never gives me an error message or something. But that's normally the case when there is no data to return.
This is InnoDB, if that helps.
Thanks for your input.
Your query does not work because you are using AND and the trim_id cannot have two different values at the same time, so you need to apply Relational Division to get the result.
You will need to use something similar to the following:
SELECT version_id
FROM yourtable
WHERE trim_id in (25, 30)
group by version_id
having count(distinct trim_id) = 2
See SQL Fiddle with Demo.
This will return the version_id values that have both 25 and 30. Then if you wanted to include additional columns in the final result, you can expand the query to:
select t1.version_id, t1.trim_id
from yourtable t1
where exists (SELECT t2.version_id
FROM yourtable t2
WHERE t2.trim_id in (25, 30)
and t1.version_id = t2.version_id
group by t2.version_id
having count(distinct t2.trim_id) = 2);
See SQL Fiddle with Demo
SELECT *
FROM table
WHERE trim_id IN(25,30)