I have a SQL query that looks like this:
DELETE
price.*
FROM
price
JOIN
service
ON
price.service_id = service.id
WHERE
price.country_from_id NOT IN
(SELECT
country_id
FROM
carrier_zone_country
JOIN
carrier_zone
ON
carrier_zone_id = carrier_zone.id
WHERE
carrier_zone.carrier_service_id = service.carrier_service_id)
OR
price.country_to_id NOT IN
(SELECT
country_id
FROM
carrier_zone_country
JOIN
carrier_zone
ON
carrier_zone_id = carrier_zone.id
WHERE
carrier_zone.carrier_service_id = service.carrier_service_id)
I was hoping to avoid running the subquery twice by moving it into the FROM clause and giving it a name. However, that gave me syntax errors. Looking at the documentation, I can see that only the SELECT FROM clause can have a named subquery in it.
Firstly I am wondering why that is the case? And secondly, how could I re-write this SQL query to avoid performing the same subquery twice.
Do one single NOT EXISTS sub-query, where both to and from countries are checked:
DELETE
price.*
FROM
price
JOIN
service
ON
price.service_id = service.id
WHERE
NOT EXIST(SELECT
1
FROM
carrier_zone_country
JOIN
carrier_zone
ON
carrier_zone_id = carrier_zone.id
WHERE country_id IN (price.country_from_id, price.country_to_id)
AND carrier_zone.carrier_service_id = service.carrier_service_id))
Related
I convert an old software (that use MS-ACCESS MDB) to mySQL.
I have a query that takes long time to run (actualy I break running after 5 minutes of waiting)
How can I write it?
SELECT pa_ID, pa_PRODUCT_ID, pr_ID,pr_NAME,Sum(pa_KILOS) as IN_KILOS,
(select sum(pl_KILOS) from POLHSH where POLHSH.pl_PRODUCT_ID = pa_PRODUCT_ID and POLHSH.pl_PARALABH_ID = pa_ID) as OUT_KILOS From PARALABH, PRODUCTS WHERE pa_company_id=1 GROUP BY pa_ID, pa_PRODUCT_ID,pr_ID, pr_NAME HAVING pa_ID=241 and pr_id=pa_PRODUCT_ID
Thanks in advance
Consider avoiding the correlated subquery which runs a SUM separately for each row and use a join of two aggregate queries each of which runs SUM once by grouping fields. Additionally, use explicit joins, the current SQL standard in joining tables/views.
Please adjust column aliases and names to actuals as assumptions were made below.
SELECT t1.*, t2.OUT_KILOS
FROM
(SELECT pa.pa_ID,
pa.pa_PRODUCT_ID,
pr.pr_ID,
pr.pr_NAME,
SUM(pa.pa_KILOS) AS IN_KILOS
FROM PARALABH pa
INNER JOIN PRODUCTS pr
ON pr.pr_id = pa.pa_PRODUCT_ID
WHERE pa.pa_company_id = 1
GROUP BY pa.pa_ID,
pa.pa_PRODUCT_ID,
pr.pr_ID,
pr.pr_NAME
HAVING pa.pa_ID = 241
) AS t1
INNER JOIN
(SELECT POLHSH.pl_PRODUCT_ID,
POLHSH.pl_PARALABH_ID
SUM(pl_KILOS) As OUT_KILOS
FROM POLHSH
GROUP BY POLHSH.pl_PRODUCT_ID,
POLHSH.pl_PARALABH_ID
) AS t2
ON t2.pl_PRODUCT_ID = t1.pa_PRODUCT_ID
AND t2.pl_PARALABH_ID = t1.pa_ID
I am working on a query with the following format:
I require all the columns from the Database 'A', while I only require the summed amount (sum(amount)) from the Database 'B'.
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ON A.CUSTNMBR = B.CUSTNMBR
GROUP BY A
ORDER BY A.CUSTNMBR
My question is regarding the grouping statement, database A has about 12 columns and to group by each individually is tedious, is there a cleaner way to do this such as:
GROUP BY A
I am not sure if a simpler way exists as I am new to SQL, I have previously investigated GROUPING_ID statements but thats about it.
Any help on lumped methods of grouping would be helpful
Since the docnumber is the primary key - just use the following SQL:
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ORDER BY RM20401.CUSTNMBR
GROUP BY A.DOCNUMBR
I have the following query:
SELECT
`tests`.`id`,
`tests`.`created_at`,
`tests`.`updated_at`,
`tests`.`created_by`,
`tests`.`date_of_test`,
`tests`.`location`,
`tests`.`information`,
`tests`.`title`,
`tests`.`goals`,
`tests`.`deleted_at`,
`tests`.`status`,
`tests`.`tester`,
`tests`.`test_approach`
FROM `tests`
WHERE
`tests`.`id` IN (
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
)
GROUP BY `tests`.`id`
ORDER BY tests.date_of_test DESC
If I run the IN query on its own, it returns
1 result
with the value 13.
the column is called "test_id"
When i run the whole above query, I get
2 results from the test table back...
with different ids... 13 and 14.
If I replace the IN query with the number 13... The SQL returns 1 result (The correct one).
What am i doing wrong here?
This query:
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
groups by wobbles.id but returns test_wobble.test_id which is not a part of GROUP BY.
On each iteration, MySQL pushes the IN field into this query:
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
-- This is implicitly added by MySQL when optimizing
AND `test_wobble`.`test_id` = `tests`.`id`
GROUP BY `wobbles`.`id`
and then just checks if some value exists.
If you remove the GROUP BY from your IN query, you'll see that it contains both 13 and 14, but only one of those is returned when you run the query with GROUP BY.
You can also try running the second query, substituting 13 and 14 instead of tests.id and make sure the query returns something in both cases.
This might actually be considered a bug in MySQL. However, since the documentation does not specify which ungrouped and unaggregated expression will be returned from a grouped query, it's better to specify it explicitly, of side effects from the optimizer will kick in like the do in this case.
Could you please provide some sample of your data and outline what are you going to achieve with the query?
It is a little bit hard to tell without knowing what the data is. But, you do have an issue in the subquery. This is your subquery:
SELECT `test_wobble`.`test_id`
FROM `project_wobble` INNER JOIN
`wobbles`
ON `project_wobble`.`wobble_id` = `wobbles`.`id` INNER JOIN
`wobble_profiles`
ON `wobble_profiles`.`wobble_id` = `wobbles`.`id` INNER JOIN
`wobble_profile_user`
ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id` INNER JOIN
`test_wobble`
ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
Note the select and group by. These have different variables:
`test_wobble`.`test_id`
`wobbles`.`id`
I'm not sure which one you really want. But MySQL returns an indeterminate value when you run the query -- and a value that can change from one run to the next. You should fix the select and group by so they match.
The inner query exposes undefined behaviour. It is explained in the documentation on the page MySQL Handling of GROUP BY.
According to the SQL standard, the inner query is invalid. To be valid, all the columns that appear in the SELECT, HAVING and ORDER BY clauses must satisfy one of the following:
they appear in the GROUP BY clause;
are used (in SELECT, HAVING or ORDER BY) only as parameters of aggregate functions;
are functionally dependent on the GROUP BY columns.
For example, using your tables, you can put in the SELECT clause:
wobbles.id - because it appears in the GROUP BY clause;
COUNT(DISTINCT project_wobble.project_id) - even if project_wobble.project_id does not appear in GROUP BY, it can be used as a parameter of the aggregate function COUNT(DISTINCT);
any column of table wobbles, given that the column id is its PK - all the columns of table wobbles are functionally dependent on wobbles.id (their values are uniquely determined by the value of wobbles.id).
Before version 5.7.5, MySQL accepts queries that do not follow the above requirements but, as the documentation states:
In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want.
Starting with version 5.7.5, MySQL implements detection of functional dependence as an configurable feature (which is turned ON by default).
On 5.7.5 your inner query will trigger an error and that's all; your query is invalid, so it doesn't run at all.
On previous versions (also on 5.7.5 if the ONLY_FULL_GROUP_BY SQL mode is disabled), the query runs but its results are unpredictable. They can change from one execution to the next if, for example, a row is deleted then re-inserted.
Because the MySQL query optimizer re-organizes your whole query for better execution plan, when it is embedded in the larger query its execution is not the same as when it is ran standalone. This is another way you can observe its undefined behaviour.
How to fix your query
Extract the inner query, remove the GROUP BY clause, add more columns to the SELECT clause and look at what it produces:
SELECT DISTINCT `test_wobble`.`wobble_id`, `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
If I'm not wrong, it will produce two rows having the same wobble_id and values 13 and 14 for column test_id.
If this result set is correct then you can remove test_wobble.wobble_id from SELECT, keep DISTINCT and put the query into the larger one.
There is no need for GROUP BY (because of the DISTINCT) and it should work faster without it.
I've got a complex (For me!) query that basically is grabbing the data from 2 tables then grouping them togeher (This bit works 100% as a SELECT query)
But when I now need to update the database in another table, it won't work.
I've got this:
UPDATE
exp_channel_data data,
(
SELECT
posts.cat_id,
posts.entry_id,
cats.cat_name,
cats.cat_id,
GROUP_CONCAT('{"',cats.cat_name, '"}:{"',cats.cat_name,'"}') as category_tag
FROM
exp_category_posts posts,
exp_categories cats
WHERE
cats.cat_id = posts.cat_id
GROUP BY
posts.entry_id
) category
SET
data.field_id_178 = category.category_tag
WHERE
data.entry_id = category.entry_id;
But I'm getting this error:
Duplicate column name 'cat_id'
I think its because i'm trying to make the connection between the two tables, BUT it's not linking.
Like I said, the SELECT query works on it's own, but when put in to the UPDATE - It just throws this error.
:(
You are very close to what you need:
UPDATE exp_channel_data data JOIN
(SELECT posts.entry_id,
GROUP_CONCAT('{"',cats.cat_name, '"}:{"',cats.cat_name,'"}') as category_tag
FROM exp_category_posts posts JOIN
exp_categories cats
ON cats.cat_id = posts.cat_id
GROUP BY posts.entry_id
) category
ON data.entry_id = category.entry_id
SET data.field_id_178 = category.category_tag;
The important part was removing cats.cat_id from the subquery. You had two columns with that name, confusing MySQL.
I also fixed the query to use proper, explicit JOIN syntax.
I have this mysql query (evolving two tables: Users and Files) that's giving me headaches:
SELECT Users.GUID, Users.Name, Users.CreationDate, Files.Date,
Count(Files.GUID) As FilesCount
FROM Users
LEFT JOIN Files ON Users.GUID = Files.UserGUID
WHERE Users.Group = '1'
When I execute it, it always return 1 row (which is not what I want). But if I remove this:
Count(Files.Date) As FilesCount
It correctly return all the rows that I expect.
I basically need to get the number of files that belongs to a user (along with the user info)
My question is: How can I fix this & make the mysql query return the user basic info along with the files count?
BTW, I'm using CodeIgniter 2 with PHP 5 (although I don't think it matters here...)
The COUNT() aggregate will return only one row in absence of a GROUP BY clause, and MySQL is lenient about the presence or contents of the GROUP BY (your query would have failed with a syntax error in most other RDBMS).
Since you have multiple columns, you ought to join against a subquery to get the count per Files.GUID. Although MySQL will permit you to GROUP BY Users.GUID without the subquery, which is simpler, you may not get the results you expect from Users.Name or Users.CreationDate. This method is more portable:
SELECT
Users.GUID,
Users.Name,
Users.CreationDate,
FileCount
FROM
Users
/* Subquery returns UserGUID and associated file count */
LEFT JOIN (
SELECT UserGUID, COUNT(*) AS FileCount
FROM Files
GROUP BY UserGUID
) fc ON Users.GUID = fc.UserGuid
WHERE Users.Group = 1
You need to group by user, otherwise it collapses all to one row: GROUP BY Users.GUID
This query has subquery which separately calculate the total Count of files for each GUID.
SELECT Users.GUID,
Users.Name,
Users.CreationDate,
Files.Date,
c.FilesCount
FROM Users
LEFT JOIN Files
ON Users.GUID = Files.UserGUID
LEFT JOIN
(
SELECT UserGUID, Count(GUID) As FilesCount
FROM Files
GROUP BY UserGUID
) c on c.UserGUID = Users.GUID
-- WHERE Users.Group = '1'