Conditionally change a join on column - php

I have this invalid mysql statement:
UPDATE third_party_raw_stock_price AS r
IF feed_link_column = 'supplier_barcode'
JOIN options_new AS o
ON o.supplier_barcode = r.supplier_option_code
END IF
IF feed_link_column = 'supplier_code'
JOIN options_new AS o
ON o.supplier_code = r.supplier_option_code
END IF
JOIN third_party_config AS c
ON SUBSTRING(o.options_id, 3, 2) = c.code
SET o.price = 9.99, o.cost_price_variation = 3.33, o.stock = 7
LIMIT 2000
How do I rewrite this to dynamically define the options_new join column? I need the join to be either ON o.supplier_code = r.supplier_option_code or ON o.supplier_barcode = r.supplier_option_code, depending on which is called for by the third_party_raw_stock_price.third_party_raw_stock_price column.

A JOIN statement is basically just a boolean test - if the result of the test (however simple or complicated it is) evaluates to true, then the records are joined. If it's false, then there's no join.
That means your join condition can be as arbitarily complex as you need it to be, as long as it boils down to a true/false value in the end:
SELECT ...
FROM bar
JOIN foo ON (foo.feed = 'barcode' AND foo.supplier = bar.supplier)
OR
(foo.feed = 'code' AND foo.code = bar.code)

Related

JOIN slow nown my Query

How can i update this query, to give me more speed?
Why is the query slower, when I use JOIN?
SELECT v.vare_id,
LEFT(v.varenavn, 25) as varenavn,
v.salgspris,
ve.enhed,
ve.vare_enhed_id,
vt.tilstand,
vt.vare_tilstand_id,
v.oko_vare,
v.varefoto
FROM vare v
JOIN vare_enhed_valg vev
ON vev.vare_id = v.vare_id
JOIN vare_enhed ve
ON ve.vare_enhed_id = vev.enhed_id
JOIN vare_tilstand_valg vtv
ON vtv.vare_id = v.vare_id
JOIN vare_tilstand vt
ON vt.vare_tilstand_id = vtv.tilstand_id
WHERE v.vare_type_id = 1
AND v.synlig = "ja"
ORDER BY v.varenavn ASC
For your query, you want an index on: vare(vare_type_id, v.synlig, v.varenavn). Other indexes might be appropriate. Let me assume that the join keys include the primary key of at least one of the tables.

PHP and MySQL - use HAVING on count or no HAVING and array_filter?

I'd like to ask if there is a good practise about performance of following.
My SQL SELECT:
SELECT avpc.category_id, a.attribute_id, ad.name, a.type, a.sort_order, avpc.attribute_value_id, avd.value, COUNT(pav.product_id) AS product_count
FROM attribute_value_per_category avpc
JOIN category_path cp ON cp.category_id = avpc.category_id
JOIN attribute_value av ON av.attribute_value_id = avpc.attribute_value_id
JOIN attribute_value_description avd ON avd.attribute_value_id = av.attribute_value_id AND avd.language_id = 2
JOIN attribute a ON a.attribute_id = av.attribute_id
JOIN attribute_description ad ON ad.attribute_id = a.attribute_id AND ad.language_id = 2
JOIN product_attribute_value pav ON pav.attribute_value_id = av.attribute_value_id
WHERE path_id = 2
GROUP BY attribute_value_id
I need to add condition: HAVING product_count > 10. I've read, that HAVING is very slow and there is no optimisation in.
So I've got these two suggestions:
Use HAVING
Not use HAVING and filter out the condition in PHP (For example by array_filter)
Would you please to give me any advice of performance of this problem?

Adding a field in a MySQL Query

I need to add a field in one of our query. I'm nt a PHP programmer buy I can get my way around a little. The query is:
if (_QUERYSTRING_) {
switch ($intMode) {
case -1:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
9 AS intmode,
Date(orders.dtimeorder) AS datepayment,
orders_costs.dbltotal AS dblamount,
orders_notes.strcod AS strtxn,
0 AS dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
'À recevoir' AS strmode,
NULL AS strvendor
FROM orders
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN orders_notes
ON orders_notes.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
WHERE date(orders.dtimeorder) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'
AND orders.boolshipped = 1
AND orders.boolcanceled = 0
AND orders_costs.boolcod = 1
AND orders_costs.dbltotal > 0
AND NOT EXISTS
(
SELECT *
FROM orders_payments
WHERE orders_payments.intorder = orders.id
AND orders_payments.intmode = 9
AND orders_payments.dblamount > 0)
GROUP BY orders.id
ORDER BY orders.dtimeorder,
orders.id");
break;
default:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
orders_payments.intmode,
Date(orders_payments.dtimepayment) AS datepayment,
orders_payments.dblamount,
orders_payments.strtxn,
orders_payments.dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
payments.strname"._LANG_." AS strmode,
payments.strvendor
FROM orders_payments
JOIN orders
ON orders.id = orders_payments.intorder
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
LEFT JOIN payments
ON payments.id = orders_payments.intmode
WHERE date(orders_payments.dtimepayment) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'".(!empty($intMode) ? "
AND orders_payments.intmode = '".$intMode."'" : NULL)."
GROUP BY orders.id,
orders_payments.intpayment
ORDER BY orders_payments.dtimepayment,
orders.id");
break;
}
The field that needs to be added is orders_addresses.intProvince so it can be displayed in the results. I tried to understand a little but I guess it's a little more complicated than I thought. It does display the province, which are numbers. My question would be, how do I "translate" those numbers by the actual names so it displays "Ontario" instead of 9? The name of the provinces are in another table called Province.
You will need to add another JOIN:
JOIN Province ON orders_addresses.intprovince = Province.x
And in the SELECT part, replace orders_addresses.intprovince by Province.y
where
x = column in table Province that holds the province id
y = column in table Province that holds the province name

right outer join between 2 tables

i have 2 tables, one is called Classes which contains the ClassName and one is called FullSchedule which contains info including ClassName, DayVal and TimeVal.
What i want to do is, i want to select the classes that are not being using in a particular day and time, and this is my query :
SELECT `Classes`.`ClassName`
FROM `FullSchedule`
RIGHT OUTER JOIN `Classes`
ON `FullSchedule`.`ClassName` = `Classes`.`ClassName`
WHERE `FullSchedule`.`DayVal` = '$day' AND `FullSchedule`.`TimeVal` = `$time`
the result is the classes that are bing used(the common ones) though im using RIGHT OUTER JOIN and even if i change it to :
ON `FullSchedule`.`ClassName` != `Classes`.`ClassName`
it shows me all classes, no matter how i change it, it either get me all of the classes or just the classes that are being used. how to i get the classes that are not being used?
Try this:
SELECT `Classes`.`ClassName`
FROM `Classes`
WHERE Classes`.`ClassName` not in (
SELECT `FullSchedule`.`ClassName`
FROM `FullSchedule`
WHERE `FullSchedule`.`DayVal` = '$day' AND `FullSchedule`.`TimeVal` = `$time` )
At first retrieve data with WHERE conditions from table FullSchedule, then RIGHT JOIN it to Classes :
SELECT
c.`ClassName`
FROM (
SELECT
`ClassName`
FROM
`FullSchedule`
WHERE
`DayVal` = '$day' AND `TimeVal` = '$time'
) f RIGHT OUTER JOIN `Classes` c
ON f.`ClassName` != c.`ClassName`
Alternative to the JOIN option:
SELECT c.ClassName
FROM Classes c
WHERE NOT EXISTS ( SELECT *
FROM FullSchedule fs
WHERE fs.DayVal = $day
AND fs.TimeVal = $time
AND fs.ClassName = c.ClassName )
I suggest you put all three solutions in your analyzer and compare the execution plans to find out which is the best fit for your environment.
If the RIGHT OUTER JOIN syntax is absolutely necessary:
SELECT c.ClassName
FROM FullSchedule fs
RIGHT OUTER JOIN Classes c
ON fs.ClassName = c.ClassName
AND fs.DayVal = $day
AND fs.TimeVal = $time
WHERE fs.ClassName IS NULL
The RIGHT OUTER JOIN ensures the Classes table returns all of its rows and then matches FullSchedule rows on ClassName and those with DayVal and TimeVal values equal to $day and $time respectively.
The WHERE clause eliminates the rows where the FullSchedule table (with the ClassName, DayVal, and TimeVal restrictions) does not have a matching record.
SELECT c.ClassName
FROM classes c
LEFT
JOIN FullSchedule s
ON s.ClassName = c.ClassName
AND s.DayVal = '$day'
AND s.TimeVal = '$time' -- <-- NOT BACKTICKS
WHERE s.ClassName IS NULL;
Consider storing dates and times as a single entity. Much, much better idea.

Query with join query, need assistance

I have three tables.
I combine the company and component tables with this code
$questions_query = "SELECT company_mast.id, component_mast.component_id
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
WHERE component_mast.component_name = '".$component_name."'
AND company_mast.company_name = '".$company_name."'";
The result is as desired, If I put company_name as Bells and component_name as Assets I get and id of 3 for Bells and an id of 9 for Assets. Now if you look at the customfields table I need to pull all the questions with the a specific company_id and component_id.
Example: If the user enters Bells and Assets they need to receive all questions with the company_id of 3 and the component_id of 9.
So this is my query
SELECT *
FROM customfield_mast
LEFT JOIN ( SELECT company_mast.id, component_mast.component_id
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
WHERE component_mast.component_name = 'Assets'
AND company_mast.company_name = 'Bells')
att
ON customfield_mast.company_id = customfield_mast.component_id
This however returns all questions in my db, which is not what I want. I'm positive my last "ON" statement is the problem, however I don't know what the correct statement would be. I have not started with SQL injection protection, this is grass roots to get my queries to work. Thanks for the help
What's wrong with another join?
SELECT company_mast.id, component_mast.component_id, CFM.DisplayName
FROM company_mast
LEFT JOIN component_mast
ON company_mast.id = component_mast.company_id
LEFT JOIN CustomField_mast CFM
ON CFM.Company_ID = Component_mast.Company_ID
and CFM.Component_ID = component_Mast.Component_ID
WHERE component_mast.component_name = '".$component_name."'
AND company_mast.company_name = '".$company_name."'";
SELECT * FROM `customfield_mast`
WHERE `company_id` =
(SELECT `id` FROM `company_mast` WHERE `company_name` = '$company_name')
AND `component_id` IN
(SELECT GROUP_CONCAT(`component_id`) FROM `component_mast`
WHERE `component_name` = '$component_name')

Categories