SQL query not show needed result - mysql

I have a SQL query where I have to query three tables (some of them twice) and I do not get the result I need:
I need to search in 'articles' for a search string ('tennis') and lookup a second table 'orderdetails' for these articles.
The hits show how much was ordered.
Now I need to check if these items were already delivered.
So I look up table 'orders' for the 'orderdetails' and look in the same table if these orders have a 'delivery'. 'orders' adn 'delivery' have a field which shows what kind it is.
So I have to check if a 'delivery' was forwarded by an 'order'.
Next check if this 'delivery' includes the 'article' and sum up the delivered articles.
If the number of delivered articles is lower than the number of ordered articles I want to show this record.
So far it works besides these items:
- [SOLVED] thanks to HLGEM 'orders' without a 'delivery' are not shown at all
- [SOLVED] 'orders' with the same amount as 'delivery' are shown but i don't want them to.
Here is what I have so far:
PrO: Process Order
PrD: Process Delivery
a: ArticleItem
p: processOrderItem
d: deliveryItem
[updated the code]
SELECT
a.Articlenumber AS Article,
PrO.Number AS Order,
PrD.Number AS Delivery,
p.Amount AS Orderamount,
SUM(d.Amount) AS Deliveryamount,
(p.Amount - Deliveryamount) AS OpenAmount
FROM Article AS a
INNER JOIN ProcessesDetails AS p
ON (a.ArticleNumber = p.Article)
AND LEFT(p.Order, 3) = 'OR-'
INNER JOIN Processes as PrO
ON PrO.Number = p.Order
AND TEXTSEARCH('Delivery:' IN PrO.Forwarded)
LEFT JOIN Processes as PrD
ON PrO.Nummer = PrD.ForwardedFrom
AND LEFT(PrD.Number,3) = 'DE-'
INNER JOIN ProcessesDetails as d
ON PrD.Number = d.Order
AND d.Article = p.Article
WHERE (a.Categorie = 'tennis')
GROUP BY(Article)
Adding the following line solved the second problem:
HAVING Deliveryamount < Orderamount

SELECT
a.Articlenumber AS Article,
PrO.Number AS Order,
PrD.Number AS Delivery,
p.Amount AS Orderamount,
SUM(d.Amount) AS Deliveryamount,
(p.Amount - Deliveryamount) AS OpenAmount
FROM Article AS a
INNER JOIN ProcessesDetails AS p ON (a.ArticleNumber = p.Article)
INNER JOIN Processes as PrO ON PrO.Number = p.Order
LEFT JOIN Processes as PrD ON PrO.Nummer = PrD.ForwardedFrom AND LEFT(PrD.Number,3) = 'DE-'
INNER JOIN ProcessesDetails as d ON PrD.Number = d.Order
WHERE (a.Categorie = 'tennis')
AND LEFT(p.Order, 3) = 'OR-'
AND TEXTSEARCH('Delivery:' IN PrO.Forwarded)AND d.Article = p.Article
GROUP BY(Article)
This will fix your left join problem.

I have no Idea what is this line in the where condition:
AND TEXTSEARCH('Delivery:' IN PrO.Forwarded)
I don't think that textsearch function exist in mysql, so try this:
SELECT
a.Articlenumber AS Article,
PrO.Number AS Order,
PrD.Number AS Delivery,
p.Amount AS Orderamount,
SUM(d.Amount) AS Deliveryamount,
(p.Amount - Deliveryamount) AS OpenAmount
FROM Article AS a
INNER JOIN ProcessesDetails AS p ON (a.ArticleNumber = p.Article)
INNER JOIN Processes as PrO ON PrO.Number = p.Order
LEFT JOIN Processes as PrD ON PrO.Nummer = PrD.ForwardedFrom
INNER JOIN ProcessesDetails as d ON PrD.Number = d.Order
WHERE (a.Categorie = 'tennis')
AND LEFT(p.Order, 3) = 'OR-'
AND PrO.Forwarded like '%Delivery:%'
AND LEFT(PrD.Number,3) = 'DE-'
AND d.Article = p.Article
GROUP BY(Article)
try using AND PrO.Forwarded like '%Delivery:%' instead of AND TEXTSEARCH('Delivery:' IN PrO.Forwarded)

The first problem is possibly related to these two lines:
LEFT JOIN Processes as PrD ON PrO.Nummer = PrD.ForwardedFrom
and
AND LEFT(PrD.Number,3) = 'DE-'
because the left join effectively has NULL values if there is no delivery there is no way that the PrD.Number can start with 'DE-'. It's possible that a where clause like:
AND (PrD.Number is null OR LEFT(PrD.Number,3) = 'DE-')
Might solve the first part of your question. Not sure about the second part of the question. I can't figure out where you're doing the numeric comparison.

Related

multiple joins, each with IN statement returns too many results

I am struggling with building mysql query so it returns right results. Idea is that i need to fetch data from main table but some of the fields are only references to other tables where also record exists in various languages.
so example code is:
SELECT cars.model
FROM cars
LEFT JOIN parts ON parts.id = cars.partId AND parts.language IN ('en', 'de')
LEFT JOIN interior ON interior.id = cars.interiorId AND interior.language IN ('en', 'de')
LEFT JOIN exterior ON exterior.id = cars.exteriorId AND exterior.language IN ('en', 'de')
LEFT JOIN wheels ON wheels.id = cars.wheelId AND wheels.language IN ('en', 'de')
LEFT JOIN extra ON extra.id = cars.extraId AND extra.language IN ('en', 'de')
WHERE cars.id IN ('72727272') AND cars.source = 1
What i need is two results from query (one in english and one in german), instead i am getting 24 results. They are in various configuration of languages.
I tried adding:
GROUP BY ... but its not working.
DISTINCT same as above
Maybe someone knows some tricks on how to deal with this kind of situation (at worst case i can execute query twice for each language but its extremely slow).
The problem you are experiencing is due to every match from parts, interior, exterior, and so on are being combined with each other regardless of language. You're getting every combination of the associated de and en data.
SELECT cars.model
FROM cars
CROSS JOIN (SELECT 'en' AS language UNION SELECT 'de') AS l
LEFT JOIN parts ON parts.id = cars.partId AND parts.language = l.language
LEFT JOIN interior ON interior.id = cars.interiorId AND interior.language = l.language
LEFT JOIN exterior ON exterior.id = cars.exteriorId AND exterior.language = l.language
LEFT JOIN wheels ON wheels.id = cars.wheelId AND wheels.language = l.language
LEFT JOIN extra ON extra.id = cars.extraId AND extra.language = l.language
WHERE cars.id IN ('72727272')
AND cars.source = 1
Also, I am assuming the full query you are attempting SELECTs more than just cars.model; otherwise, all this JOINing is pointless.
Could you try putting join condition on language as well like below:
SELECT distinct cars.model
FROM cars
LEFT JOIN parts ON parts.id = cars.partId AND parts.language IN ('en', 'de')
LEFT JOIN interior ON interior.id = cars.interiorId AND interior.language =parts.language
LEFT JOIN exterior ON exterior.id = cars.exteriorId AND exterior.language =parts.language
LEFT JOIN wheels ON wheels.id = cars.wheelId AND wheels.language =parts.language
LEFT JOIN extra ON extra.id = cars.extraId AND extra.language =parts.language
WHERE cars.id IN ('72727272') AND cars.source = 1
As you require result in either english or german, it will make sure only english language or german language results are joined.

Issue With Join Doubling Results

I have seen several posts about this on Stack Overflow, but none of them seems to give me an answer that I can understand.
I am trying to join several relations together in order to get all of the relevant information to output all routes that start in China and end in the United States.
In the SeaRoute relation, the start_port and end_port are stored as INT and in the Port relation the pid corresponds to the start_port and end_port and includes a pcountry column.
I am starting off with just trying to output everything that has a start_port that is in China. I am expecting 3 results from my Record relation as those are the only ones that start with China in the table; However, I am receiving 6 records at the output (all of the results appear to have been doubled if I go back and audit what's in the table).
While I want the right answer, I am more concerned that I have a fundamental misunderstanding of Inner Join and the other Join methods. What am I doing wrong?
SELECT *
FROM Record
INNER JOIN Goods AS Go_data
ON Record.gid = Go_data.gid
LEFT JOIN SeaRoute AS SR
ON Record.rid = SR.rid
RIGHT JOIN (SELECT pid, pcountry AS starting_port_country
FROM Port
INNER JOIN SeaRoute AS SR ON Port.pid = SR.start_port
WHERE Port.pcountry = 'China')
AS start_port_table ON SR.start_port = start_port_table.pid
From the looks of your query, you want to be INNER JOINing between the records that you have only on the routes that you want.
You know all of the SeaRoutes that start in China and end in the United States already, you do however need to join to the Ports table twice like so:
SELECT sr.rid,
sp.pcountry AS starting_port_country,
ep.pcountry AS end_port_country
FROM dbo.SeaRoute sr
INNER JOIN dbo.Port sp ON sp.pid = sr.start_port
INNER JOIN dbo.Port ep ON ep.pid = sr.end_port
WHERE sp.pcountry = 'China'
AND ep.pcountry = 'United States'
Then you just need to join that to your main query:
SELECT *
FROM Record
INNER JOIN dbo.Goods AS Go_data ON Record.gid = Go_data.gid
INNER JOIN
(
SELECT sr.rid,
sp.pcountry AS starting_port_country,
ep.pcountry AS end_port_country
FROM dbo.SeaRoute sr
INNER JOIN dbo.Port sp ON sp.pid = sr.start_port
INNER JOIN dbo.Port ep ON ep.pid = sr.end_port
WHERE sp.pcountry = 'China'
AND ep.pcountry = 'United States'
) ports ON ports.rid = Record.rid
There's no way I can explain joins to you any clearer than this page can:
https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

How to join a few tables without repeat?

I have a SQL query that left joins a few tables in different ways depending on a conditions.
SELECT
dh_partner.company_name,
dh_partner_abonnement.name,
dh_partner_abonnement.description,
dh_partner_abonnement.price,
dh_partner_abonnement.discount_price,
dh_studio.partner_id,
CONCAT('https://some.url/images/studio/logo/', dh_studio.logo) as logo_url,
CONCAT('https://some.url/studio/', dh_studio.alias) as page_url,
CONCAT('https://some.url/order/abonnement/', dh_studio.alias, '/', dh_partner_abonnement_studios.abonnement_id) as checkout_url
FROM dh_partner_abonnement
LEFT JOIN dh_partner on dh_partner.id = dh_partner_abonnement.partner_id
LEFT JOIN dh_studio on dh_studio.partner_id = dh_partner.id
LEFT JOIN dh_partner_abonnement_studios on dh_partner_abonnement_studios.studio_id = dh_studio.id
WHERE
dh_partner.status = 'active'
and dh_partner.id = dh_studio.partner_id
and dh_partner.city_id = '1'
and dh_partner_abonnement_studios.studio_id = dh_studio.id
and dh_studio.show_status = '1'
The challenge in the following code
CONCAT('https://some.url/ru/order/abonnement/', dh_studio.alias, '/', dh_partner_abonnement_studios.abonnement_id) as checkout_url
LEFT JOIN dh_partner_abonnement_studios on dh_partner_abonnement_studios.studio_id = dh_studio.id
and dh_partner_abonnement_studios.studio_id = dh_studio.id
It repeats to the each dh_partner_abonnement this column dh_partner_abonnement_studios.abonnement_id
I have to connect them correctly. I know that I need to use if, however having no idea how.
Just guessing from the table names:
SELECT
p.company_name,
pa.name,
pa.description,
pa.price,
pa.discount_price,
s.partner_id,
CONCAT('https://some.url/images/studio/logo/', s.logo) as logo_url,
CONCAT('https://some.url/studio/', s.alias) as page_url,
CONCAT('https://some.url/order/abonnement/', s.alias, '/', pa.abonnement_id)
as checkout_url
FROM dh_partner_abonnement pa
JOIN dh_partner_abonnement_studios pas ON pas.partner_id = pa.partner_id
AND pas.abonnement_id = pa.abonnement_id
JOIN dh_studio s ON s.id = pas.studio_id
AND s.show_status = 1
JOIN dh_partner p ON p.id = pa.partner_id
AND p.status = 'active'
AND p.city_id = 1
You haven't joined dh_partner_abonnement and dh_partner_abonnement_studios on the complete key, which should include the abonnement_id.
It also seems a studio has a partner_id to indicate that it belongs to a certain partner. However, in your query you are interested in the abbonement studios, so join the studio on the abbonement's studio_ids.

Simple query issue with multiple tables and mismatching IDs

I'm having trouble with a simple MySQL Query.
Here is the query:
SELECT distinct e.E_CODE, s.S_CODE, p.P_ID, p.P_NAME, p.P_FIRSTNAME, p.P_STATUS, e.E_BOSS, tp.TP_TITLE
from event_participation ep, worker p, type_participation tp, event e, section s
where ep.P_ID = p.P_ID
and s.S_ID = e.S_ID
and ep.TP_ID = tp.TP_ID
and e.E_CODE = ep.E_CODE
The problem is that ep.TP_ID sometimes has a value set to zero while tp.TP_ID has nothing with a zero ID. It's auto-increment and starts at 1 and so on.
The result is obviously that this query does not return records when the ep.TP_ID = 0 and there is no match in tp.TP_ID.
So I'm trying to figure out a way to get those results in there anyway. I was thinking of using a LEFT JOIN statement but couldn't figure out a proper way to insert it into the query.
Any advice on this matter would be greatly appreciated.
First of all, I advice you to use some general type for event_participation records without type; But, unless to take that decision, supposing you want to get all matching records between all tables but also get results with no type, you can use the following query:
SELECT DISTINCT e.E_CODE, s.S_CODE, p.P_ID, p.P_NAME, p.P_FIRSTNAME, p.P_STATUS, e.E_BOSS, tp.TP_TITLE
FROM event_participation ep
JOIN worker p ON (ep.P_ID = p.P_ID)
JOIN event e ON (e.E_CODE = ep.E_CODE)
JOIN section s ON (s.S_ID = e.S_ID)
LEFT JOIN type_participation tp ON (ep.TP_ID = tp.TP_ID)
SELECT DISTINCT e.E_CODE
, s.S_CODE
, p.P_ID
, p.P_NAME
, p.P_FIRSTNAME
, p.P_STATUS
, e.E_BOSS
, tp.TP_TITLE
FROM event_participation ep
JOIN worker p
ON p.P_ID = ep.P_ID
JOIN event e
ON e.E_CODE = ep.E_CODE
JOIN section s
ON s.S_ID = e.S_ID
LEFT
JOIN type_participation tp
ON tp.TP_ID = ep.TP_ID;

Assistance with MySQL Query - Omitting, Grouping?

Doing a bit of investigation and writing a query against a logs db.
I've joined a number of tables to bring back the data that I need, but i'd like to clean it up a bit.
The query returns all the users and which features they have enabled on their account.
Here is what i'm trying to do to clean it up:
Their is a column called 'actions' which has two states, 'added' and 'removed'
If a user feature has an action of 'removed' then I want to not show any of the rows for the same feature for that user which are also marked as 'added'
Is this possible?!
Here is what I have so far:
select users.id as site_id, users.company_name, feature_log.featurecode, feature.minimum_account as feature_type, users.account_type as site_type, account_types.name as account, feature_log.action, feature_log.time
from users
inner join
feature_log
on users.id = feature_log.siteid
inner join
feature
on feature_log.featurecode = feature.featurecode
inner join account_types
on users.account_type_INC = account_types.id
where feature.minimum_account != 0
AND feature.minimum_account > users.account_type
AND users.status = 'Y'
ORDER BY feature_log.time DESC
Thanks for any support!
So, in order to "mute" all the features, that have been "removed" at any point in time for a given user, you can add a (left) join on the following subquery:
SELECT DISTINCT users.id as siteid, feature_log.featurecode, TRUE as mute_feature
FROM users
INNER JOIN feature_log ON (users.id = feature_log.siteid)
WHERE action = 'removed'
This will be the list of features that a given user disabled at some point in time. Then in your query's WHERE clause, you'd add a filter like so:
AND NOT IFNULL(mute_feature, FALSE)
Essentially, that'd bring your whole query to be:
select users.id as site_id, users.company_name, feature_log.featurecode, feature.minimum_account as feature_type, users.account_type as site_type, account_types.name as account, feature_log.action, feature_log.time
from users
inner join
feature_log
on users.id = feature_log.siteid
left join (
SELECT DISTINCT users.id as siteid, feature_log.featurecode, TRUE as mute_feature
FROM users
INNER JOIN feature_log ON (users.id = feature_log.siteid)
WHERE action = 'removed'
) as muted_features ON (feature_log.siteid = muted_features.siteid AND feature_log.featurecode = muted_features.featurecode)
inner join
feature
on feature_log.featurecode = feature.featurecode
inner join account_types
on users.account_type_INC = account_types.id
where feature.minimum_account != 0
AND feature.minimum_account > users.account_type
AND users.status = 'Y'
AND NOT IFNULL(mute_feature, FALSE)
ORDER BY feature_log.time DESC