getting different values, by condition becoming more specific - mysql

I have two pieces of code
SELECT * FROM etel.ti18n_country
inner join etel.ti18n
ON id_i18nid = i18nid WHERE id_countryid = 1
and
SELECT * FROM etel.ti18n_country
inner join etel.ti18n
ON id_i18nid = i18nid WHERE id_countryid = 1 and id_i18nid = 4460;
the first results in a bunch of results, but noticably none with id_i18nid = 4460
the second, however gets the result with id_i18nid = 4460.
how can that be? As I understand mysql the first piece of code should've had a result id_i18nid = 4460 for it to be possible for the second piece to have it aswell. Since I made the where clause more specific

Turns out the problem was that I was using Datagrips' ordering to find my id. since I had more than 500 results, datagrip takes random results and orders those. by ending the statement with ORDER BY id_i18nid DESC I found the result.

Related

Subquery returns more than one row error when one row is returned

I am currently doing some SQL magic and wanted to update the stock in my companies ERP program. However if I try to run the following query I get the error mentioned in the title.
update llx_product lp
set stock = (select sum(ps.reel)
from llx_product_stock as ps, llx_entrepot as w
where w.entity IN (1)
and w.rowid = ps.fk_entrepot
and ps.fk_product = lp.rowid
group by ps.rowid)
The subquery by itself returns just one row if used with a rowid for the product.
select sum(ps.reel)
from llx_product_stock as ps, llx_entrepot as w
where w.entity in (1)
and w.rowid = ps.fk_entrepot
and ps.fk_product = 7372
group by ps.rowid
Any help would be appreciated
I would suggest writing the query as:
update llx_product lp
set stock = (select sum(ps.reel)
from llx_product_stock ps join
llx_entrepot w
on ps.fk_product = lp.rowid
where w.entity in (1) and
w.rowid = ps.fk_entrepot
);
An aggregation query with no group by cannot return more than one row. It is unclear how your version is returning more than one row because the key used in the group by also has an equality comparison. Perhaps there is some type conversion issue at play.
But in any case, without the group by, you cannot get the error you are currently getting.
For anyone wondering the solution to my issue was a very simple query, Gordon pointed in the right direction and I made it harder than it should be.
update llx_product lp
left join llx_product_stock ps on lp.rowid = ps.fk_product
set lp.stock = ps.reel

SQL - OutterApply and Left Join

I'm working with a large stored procedure, I'm having trouble with a small portion of it.
When I execute a query on the table im joining, there can be 0, 1 or 2 results. If there are 0 results, I don't really care, my code returns null values, no big deal. If there is 1 result, my code returns the correct values, however, if there are 2 results, I am having trouble selecting the second result.
My code below works until the second OutterApply(the AHM2 stuff). Does anyone see what I am doing wrong?
The animal ID is identical for both OuterApplys. I just need to return the second result, if there is one, and if it is not the same as the first one.
SELECT TOP 1
AHM.AnimalHerdManagementId,
AHM.HerdManagementId,
AHM2.AnimalHerdManagementId,
AHM2.HerdManagementId,
HM.Code AS HerdManagementCode,
HM2.Code AS HerdManagementCode2
OUTER APPLY
(
SELECT TOP 1 AHM.AnimalHerdManagementId, AHM.HerdManagementId
FROM dbo.AnimalHerdManagement AHM
WHERE AHM.AnimalId = A.AnimalId AND ISNULL(AHM.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM.EffectiveFrom DESC
) AHM
LEFT JOIN dbo.HerdManagement HM ON AHM.HerdManagementId = HM.HerdManagementId
OUTER APPLY
(
SELECT TOP 1 AHM2.AnimalHerdManagementId, AHM2.HerdManagementId
FROM dbo.AnimalHerdManagement AHM2
WHERE AHM2.AnimalId = A.AnimalId AND AHM2.AnimalHerdManagementId != AHM.AnimalHerdManagementId AND ISNULL(AHM2.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM2.EffectiveFrom DESC
) AHM2
LEFT JOIN dbo.HerdManagement HM2 ON AHM2.HerdManagementId = HM2.HerdManagementId
I think I can help you with the OUTER APPLY but the method of getting the two different values is going to need some help as my solution is a total hack.
First, you don't need to join on the outer apply. The join is implied. So you can completely eliminate the join syntax from your query.
Second, AnimalHerdManagement looks/seems like a special table called a Junction Table. All the data contained in it is contained elsewhere (That it contains completely redundant data is why it's called a special table). But that is minor.
Finally, here is some example code I threw together that accomplishes what you are after. The method I am using to retrieve different results on the two outer apply's is a hack, but if you are sure that will always be true, it might work. I am not able to get a multi-level outer apply to work.
select * from AH_Animal A
outer apply
(
select max (HerdManagementID) as HerdMgmtID1 from AH_AnimalHerdManagement HM1 where HM1.AnimalID = A.AnimalID
) as z
outer apply
(
select min (HerdManagementID) as HerdMgmtID2 from AH_AnimalHerdManagement HM2 where HM2.AnimalID = A.AnimalID
) as zz
I hope that helped. There has to be another solution to this, as this would not work at all if you ever expected 3 results.
Query Results:

MySQL: Subquery returns more than 1 row

I know this has been asked plenty times before, but I cant find an answer that is close to mine.
I have the following query:
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, o.organisation_name
FROM db_cases c, db_custinfo ci, db_organisation o
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2'
AND organisation_name = (
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
)
AND s.sites_site_ID = c.sites_site_ID)
What I am trying to do is is get the cases, where the sites_site_ID which is defined in the cases, also appears in the db_sites sites table alongside its organisation_ID which I want to filter by as defined by "organisation_ID = '111'" but I am getting the response from MySQL as stated in the question.
I hope this makes sense, and I would appreciate any help on this one.
Thanks.
As the error states your subquery returns more then one row which it cannot do in this situation. If this is not expect results you really should investigate why this occurs. But if you know this will happen and want only the first result use LIMIT 1 to limit the results to one row.
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
LIMIT 1
Well the problem is, obviously, that your subquery returns more than one row which is invalid when using it as a scalar subquery such as with the = operator in the WHERE clause.
Instead you could do an inner join on the subquery which would filter your results to only rows that matched the ON clause. This will get you all rows that match, even if there is more than one returned in the subquery.
UPDATE:
You're likely getting more than one row from your subquery because you're doing a cross join on the db_sites and db_cases table. You're using the old-style join syntax and then not qualifying any predicate to join the tables on in the WHERE clause. Using this old style of joining tables is not recommended for this very reason. It would be better if you explicitly stated what kind of join it was and how the tables should be joined.
Good pages on joins:
http://dev.mysql.com/doc/refman/5.0/en/join.html (for the right syntax)
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html (for the differences between the types of joins)
I was battling this for an hour, and overcomplicated it completely. Sometimes a quick break and writing it out on an online forum can solve it for you ;)
Here is the query as it should be.
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, c.sites_site_ID
FROM db_cases c, db_custinfo ci, db_sites s
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2' AND (s.organisation_ID = '111' AND s.sites_site_ID = c.sites_site_ID)
Let me re-write what you have post:
SELECT
c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName,
c.cases_timestamp, c.sites_site_ID
FROM
db_cases c
JOIN
db_custinfo ci ON c.userInfo_ID = ci.userinfo_ID and c.cases_status = '2'
JOIN
db_sites s ON s.sites_site_ID = c.sites_site_ID and s.organization_ID = 111

Improve terrible annotate() query

Here is the current query I have that orders an order_item by the most recent timestamp.
order_items.annotate(newest_note_time=Max('ordernotes__timestamp')).
order_by('newest_note_time')
It works. However, in viewing it in debug-toolbar it is giving me two brutal queries, that are all but identical. I have tried doing:
order_items = order_items.order_by('-ordernotes__timestamp')
But that results in an incorrect query that gives me duplicate results.
Is there a better way to do this query without jumping into raw SQL here?
Here is one of the queries (the second is basically identical, no idea why it generates a second...)
SELECT ••• FROM `order_orderitem`
INNER JOIN `order_orderitemstatus` ON (`order_orderitem`.`status_id` = `order_orderitemstatus`.`id`)
INNER JOIN `order_order` ON (`order_orderitem`.`order_id` = `order_order`.`id`)
INNER JOIN `title_title` ON (`order_orderitem`.`title_id` = `title_title`.`id`)
INNER JOIN `home_service` ON (`order_orderitem`.`service_id` = `home_service`.`id`)
LEFT OUTER JOIN `order_ordernotes` ON (`order_orderitem`.`id` = `order_ordernotes`.`order_item_id`)
WHERE NOT (`order_orderitemstatus`.`name` IN ('Complete', 'Live', 'Archived'))
GROUP BY
`order_orderitem`.`id`, `order_orderitem`.`order_id`, `order_orderitem`.`title_id`, `order_orderitem`.`service_id`,
`order_orderitem`.`metadata_locale_id`, `order_orderitem`.`purchase_order`, `order_orderitem`.`due_date`, `order_orderitem`.`feature`,
`order_orderitem`.`trailer`, `order_orderitem`.`artwork`, `order_orderitem`.`chaptering`, `order_orderitem`.`cc`,
`order_orderitem`.`metadata`, `order_orderitem`.`subtitles`, `order_orderitem`.`forced_narrative`, `order_orderitem`.`qc_note`,
`order_orderitem`.`audio`, `order_orderitem`.`dub_card`, `order_orderitem`.`live_url`, `order_orderitem`.`metadata_valid`,
`order_orderitem`.`status_id`, `order_orderitem`.`date_created`, `order_order`.`id`, `order_order`.`number`, `order_order`.`provider_id`,
`order_order`.`date_created`, `order_order`.`date_ordered`, `order_order`.`is_archived`, `title_title`.`id`, `title_title`.`film_id`,
`title_title`.`name`, `title_title`.`provider_id`, `title_title`.`original_locale_id`, `title_title`.`country_of_origin_id`,
`title_title`.`synopsis`, `title_title`.`production_company`, `title_title`.`copyright`, `title_title`.`run_time`,
`title_title`.`original_theatrical_release`, `title_title`.`color`, `title_title`.`film_type`, `title_title`.`no_cc_reason`,
`title_title`.`includes_hd`, `title_title`.`provider_identifier`, `title_title`.`episode_production_number`, `title_title`.`container_position`,
`title_title`.`season_id`, `home_service`.`id`, `home_service`.`name`, `home_service`.`notes`, `order_orderitemstatus`.`id`,
`order_orderitemstatus`.`name`, `order_orderitemstatus`.`department_id`, `order_orderitemstatus`.`is_finished`,
`order_orderitemstatus`.`ordering` ORDER BY NULL
.select_related(depth=1)
Add that to the end of your original query and see if any magic happens.
Another possible fix for awful queries that I have is to just cache the page. Add the following to the top of your file:
from django.views.decorators.cache import cache_page
and then just above your def... add:
#cache_page(60 * 5)
which is 60 seconds * 5, for 5 minutes. Change the time to whatever is appropriate for you.

MYSQL: How to use outer aliases in subquery properly?

The first query works just fine. It returns one row from the table 'routepoint'. It has a certain 'route_id' and 'geo_distance()' is on its minimum given the parameters. I know that the subquery in the FROM section seems unnecessarily complicated but in my eyes it helps to highlight the problem with the second query.
The differences are in the last two rows.
SELECT rp.*
FROM routepoint rp, route r, (SELECT * FROM ride_offer WHERE id = 6) as ro
WHERE rp.route_id = r.id
AND r.id = ro.current_route_id
AND geo_distance(rp.lat,rp.lng,52372070,9735690) =
(SELECT MIN(geo_distance(lat,lng,52372070,9735690))
FROM routepoint rp1, ride_offer ro1
WHERE rp1.route_id = ro1.current_route_id AND ro1.id = 6);
The next query does not work at all. It completely freezes mysql and I have to restart.
What am I doing wrong? The first subquery returns excactly one row. I don't understand the difference.
SELECT rp.*
FROM routepoint rp, route r, (SELECT * FROM ride_offer WHERE id = 6) as ro
WHERE
rp.route_id = r.id
AND r.id = ro.current_route_id
AND geo_distance(rp.lat,rp.lng,52372070,9735690) =
(SELECT MIN(geo_distance(lat,lng,52372070,9735690))
FROM routepoint rp1
WHERE rp1.route_id = ro.current_route_id);
The problem is, as pointed out by Romain, that this is costly.
This article describes an algorithm that reduces the cost by a 2-step process.
Step 1: Find a bounding box that contains at least one point.
Step 2: Find the closest point by examining all points in the bounding box, which should be a comparatively small number, thus not so costly.