Combine the results of two SQL queries - php

How can I combine the results of these two sql queries either in SQL or PHP .. they're all involving joins .. I would like to combine them both and sort them by orderid .. how can I do that ?
first query
$sqlstr = "SELECT op.* FROM products_to_products_extra_fields AS p
INNER JOIN orders_roster AS r ON p.products_id = r.products_id
INNER JOIN orders_products AS op ON r.orders_id = op.orders_id
INNER JOIN orders AS o on op.orders_id = o.orders_id
WHERE p.products_extra_fields_id = 14
AND p.products_extra_fields_value between '"
. tep_db_input($startdate) . "' and '"
. tep_db_input($enddate) . " 23:59:59'
AND r.roster_status != 'Removed'
AND o.payment_method = 'Institutional Billing'
AND o.orders_status < 100001
GROUP BY o.orders_id
ORDER BY DECODE(o.cc_type, '$salt') ASC";
SECOND query
$sqlstr2 = "SELECT op.* FROM products_to_products_extra_fields AS p
INNER JOIN orders_products AS op ON p.products_id = op.products_id
INNER JOIN orders AS o on op.orders_id = o.orders_id
WHERE p.products_id IN
(SELECT products_id
FROM products_to_products_extra_fields
WHERE p.products_id NOT IN
(SELECT products_id
FROM products_to_products_extra_fields
WHERE products_extra_fields_id = 14)
)
AND o.date_purchased between '"
. tep_db_input($startdate) . "' and '"
. tep_db_input($enddate) . " 23:59:59'
AND o.payment_method = 'Institutional Billing'
AND o.orders_status < 100001
GROUP BY o.orders_id
ORDER BY DECODE(o.cc_type, '$salt') ASC";

If you need them combined on the PHP end, I am going to assume you are left with an array of arrays (MySQL Rows), which you could simply loop through both sets of results and use array_push to push them into 3rd(complete) array. You could also toy around with array_merge but sometimes with multidimensional arrays the end result isnt what you expected.
http://us3.php.net/manual/en/function.array-push.php
http://us3.php.net/function.array-merge

Just make a UNION query and get the results merged on the SQL side. No PHP needed.

Related

MySQL count issue

In my application (osCommerce) I had to modify a query that look like this:
SELECT sql_cache distinct p.products_image,
p.products_subimage1,
pd.products_name,
p.products_quantity,
p.products_model,
p.products_ordered,
p.products_id,
p.products_price,
p.products_date_added,
p.products_weight,
p.products_length,
p.products_width,
p.products_height,
p.products_tax_class_id,
p.products_status,
IF(s.status, s.specials_new_products_price, NULL) AS specials_new_products_price,
IF(s.status, s.specials_new_products_price, p.products_price) AS final_price
FROM products p
LEFT JOIN specials s
ON p.products_id = s.products_id
LEFT JOIN products_to_categories p2c
ON p.products_id=p2c.products_id
LEFT JOIN products_description pd
ON p.products_id=pd.products_id
INNER JOIN filter_association_products fap
ON p.products_id =fap.products_id
LEFT JOIN products_attributes pa
ON p.products_id = pa.products_id
WHERE p.products_status = '1'
AND date_sub(curdate(),INTERVAL 3000 day) <= p.products_date_added
AND find_in_set(fap.filter_id,'126, 130')
ORDER BY p.products_date_added DESC,
pd.products_name
to end like this, for accurate results:
AND fap.filter_id IN (126, 130)
GROUP BY p.products_id
HAVING COUNT(DISTINCT fap.filter_id) = 2;
The issue I have now is that there is the following query that is using this new query and giving me wrong results.
SELECT COUNT( DISTINCT p.products_id ) AS total
FROM products p
LEFT JOIN specials s ON p.products_id = s.products_id
LEFT JOIN products_to_categories p2c
ON p.products_id = p2c.products_id
LEFT JOIN products_description pd
ON p.products_id = pd.products_id
INNER JOIN filter_association_products fap ON p.products_id = fap.products_id
LEFT JOIN products_attributes pa
ON p.products_id = pa.products_id
WHERE p.products_status = '1'
AND DATE_SUB( CURDATE( ) , INTERVAL 3000 DAY ) <= p.products_date_added
AND fap.filter_id IN ( 126, 130 )
GROUP BY p.products_id
HAVING COUNT( DISTINCT fap.filter_id ) =2
ORDER BY p.products_date_added DESC , pd.products_name
Which instead of giving a result of 1 row with the count of all the product_ids in the original query, now gives a result of multiple rows (the same amount of rows as the expected total products count) with the number 1 in each of them.
The main issue seems to be the GROUP BY p.products_id
HAVING COUNT( DISTINCT fap.filter_id ) =2
Is there any way to modify the original query so that the count query will work correctly while still using AND fap.filter_id IN ( 126, 130 )?
You need to use a subquery to get the results that you want:
select count(*)
from (<old query here>) s;
You need to aggregate at the product id level to get the products that meet the original condition. Counting the number of such products requires another aggregation.
As Gordon suggested, using a subquery should generally work.
Since this query looks like a product listing query and since you are using osCommerce, you will bump into another core issue when you modify the query to use a subquery:
The count query of the split page results will fail as it does not support subqueries.
To resolve this also, you will need to modify the core code in catalog/includes/classes/split_page_results.php
Change:
$count_query = tep_db_query("select count(" . $count_string . ") as total " . substr($this->sql_query, $pos_from, ($pos_to - $pos_from)));
To:
$count_query = tep_db_query("select count(*) as total from (" . $this->sql_query . ") AS derivedtable1");
More details here: http://forums.oscommerce.com/topic/290110-class-splitpageresults/

MySQL query, add new alias

I have a mysql query using for search script and i need to add another field (like SPV.term alias) This code is tell me an Error Number: 1054 Unknown column 'S.id' in 'on clause'.
$query = "
SELECT
SP.url,
SP.id,
S.name,
SP.hit,
SP.hot,
SP.action,
SP.id,
SP.smallimage,
SP.mainmodimage,
(SELECT
stock
FROM shop_product_variants
WHERE shop_product_variants.product_id = S.id
AND stock > 0
LIMIT 1) as stock,
(SELECT
price
FROM shop_product_variants
WHERE shop_product_variants.product_id = S.id
OR shop_product_variants.product_id = S.id
AND stock = 0
LIMIT 1) as price,
(SELECT
id
FROM shop_product_variants
WHERE shop_product_variants.product_id = S.id
OR shop_product_variants.product_id = S.id
AND stock = 0
LIMIT 1) as v_id,
(SELECT
old_price
FROM shop_product_variants
WHERE shop_product_variants.product_id = S.id
AND stock > 0
LIMIT 1) as old_price
FROM shop_products_i18n S,
shop_product_variants SPV
INNER JOIN shop_products SP
ON SP.id = S.id
WHERE SP.active = 1
AND S.name LIKE '%" . $get . "%'
OR SP.url LIKE '%" . $get . "%'
OR SPV.term LIKE '%" . $get . "%'
GROUP BY S.id
ORDER BY stock DESC
";
This is your from clause:
FROM shop_products_i18n S,
shop_product_variants SPV INNER JOIN
shop_products SP
ON SP.id = S.id
The problem is that you are mixing old-style joins and new-style joins. A simple rule: Never use a commas in the from clause.
I think you really mean:
FROM shop_products_i18n S INNER JOIN
shop_products SP
ON SP.id = S.id
Because you don't use SPV anywhere else in the outer query, except for the where clause. That condition should probably go into each of the subqueries.
By the way, you can fix the original problem by replacing the , with cross join:
FROM shop_products_i18n S CROSS JOIN
shop_product_variants SPV INNER JOIN
shop_products SP
ON SP.id = S.id
Although , and cross join both perform cartesian products, they behave differently in the FROM clause in terms of precedence. The problem that you have with the , is that the precedence rules say the following INNER JOIN is parsed first -- so the columns in S are not available.

MySQL Sum with Join

I have been trying to do a sum with a join with no luck. What I need is to get a total from product_price (located in tbl_products) based on a product_id which is located in both tbl_basket and tbl_products.
So far I have:
$result = mysql_query("SELECT * FROM tbl_basket a INNER JOIN tbl_products b ON a.product_id = b.product_id WHERE a.customer_id = '" . $_SESSION['user'] . "'");
This works to get the product_name from tbl_products based on the product_id stored in tbl_basket. I know I need a COUNT which I have tried numerous ways but with no luck. I have chosen to show a query I know works for something as my syntax for the COUNT I tried was way off. Thank you.
Does this not work?
$result = mysql_query("SELECT sum(b.product_price) as total_price FROM tbl_basket a INNER JOIN tbl_products b ON a.product_id = b.product_id WHERE a.customer_id = '" . $_SESSION['user'] . "'")

MySQL: Show latest value when using GROUP BY

My table "orders" includes the date_purchased and my table "orders_products" includes the products_id for the specific order.
I want to list a specific client's all purchased products_id (not all orders!) showing the latest date_purchased for each products_id. The list should be ordered with the latest orders_id of these at the top.
The code below will show all unique products_id as I want, but the "group by" is resulting in not showing the latest orders_id or date_purchased for each products_id…
What am I missing here?
SELECT o.orders_id, o.date_purchased, op.products_id
FROM orders o, orders_products op
WHERE o.customers_id = '" . $client_id . "' and op.orders_id = o.orders_id
GROUP BY op.products_id
ORDER BY orders_id DESC
The not exists approach is often the most efficient approach for this type of query:
SELECT o.orders_id, o.date_purchased, op.products_id
FROM orders o join
orders_products op
on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "' and
not exists (select 1
from orders o2 join
orders_products op2
on op2.orders_id = o2.orders_id
where op2.products_id = op.products_id and
o.customers_id = '" . $client_id . "' and
o2.orders_id > o.orders_id
)
ORDER BY orders_id DESC;
The logic is: "Get me all rows from orders where there is no row with the same product and a larger id." This is equivalent to saying: "Get me the max row".
For best performance, you want an index on orders(products_id, orders_id).
EDIT:
There is another approach that uses subtring_index() and group_concat(). This might be the most efficient way, if the filter on customer_id is highly selective (that is, greatly reduces the number of rows).
SELECT max(o.orders_id) as orders_id,
substring_index(group_concat(o.date_purchased order by orders_id desc), ',', 1) as date_purchased,
op.products_id
FROM orders o join
orders_products op
on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "'
GROUP BY op.products_id;
Of course, if the date purchased and orders_id are both increasing, you can simplify this to using max() for both:
SELECT max(o.orders_id) as orders_id,
max(o.date_purchased) as date_purchased,
op.products_id
FROM orders o join
orders_products op
on op.orders_id = o.orders_id
WHERE o.customers_id = '" . $client_id . "'
GROUP BY op.products_id;
Using group by the result will be grouped in un-ordered way you cannot rely on that using group by will give you the latest result in each so for this you need to first get the maximum of purchase date and then join with your orders table with using additional condition in on clause
SELECT
o.orders_id,
o.date_purchased,
oo.products_id
FROM
orders o
INNER JOIN (
SELECT orders.orders_id, MAX(orders.date_purchased) date_purchased ,orders_products.products_id
FROM orders
INNER JOIN
orders_products
ON(orders_products.orders_id = orders.orders_id)
GROUP BY orders.orders_id ,orders_products.products_id
) oo
ON( oo.orders_id = o.orders_id AND oo.date_purchased=o.date_purchased)
WHERE o.customers_id = '" . $client_id . "'
ORDER BY o.orders_id DESC
This will give the latest orders per products of customer
You might try this? Cannot test it right now.
SELECT MAX(o.orders_id), MAX(o.date_purchased), op.products_id
FROM orders o, orders_products op
WHERE o.customers_id = 1 and op.orders_id = o.orders_id
GROUP BY op.products_id

How to combine two Post/Category tables MYSQL SELECT queries into one

I have two MySQL queries:
1) "SELECT ID,post_title,post_category,post_perma FROM ".TBL_POSTS."
WHERE published='1' AND page='0' ORDER BY ID DESC LIMIT 10"
2) "SELECT p.cat_ID,p.cat_nicename FROM ".TBL_CATEGORIES." n, ".TBL_CATEGORIES." p
WHERE n.lft BETWEEN p.lft AND p.rgt AND n.cat_ID='".post_category."' ORDER BY p.lft
First query selects posts and then second select the Path of the category by post_category please note that post_category will be taken from first query means post_category is common in both table.. in first table it is named as post_category and in second it is cat_ID
Right now I am running it in foreach loop which is not good. Also one thing to be noticed that second query will also return Array and that one array should correspond to post_category
Can any SQL expert help me?
Many Thanx
Please try this it might be helpful to you.
SELECT a.ID, a.post_title,a.post_category,a.post_perma, b.cat_ID, b.cat_nickname
FROM (SELECT ID,post_title,post_category,post_perma FROM ".TBL_POSTS." WHERE published='1' AND page='0' ORDER BY ID DESC LIMIT 10) a
LEFT JOIN (SELECT p.cat_ID as cat_ID,p.cat_nicename as cat_nickname FROM " . TBL_CATEGORIES . " n, " . TBL_CATEGORIES . " p WHERE n.lft BETWEEN p.lft AND p.rgt AND n.cat_ID = '" .$post_category. "' ORDER BY p.lft) b ON a.ID = b.cat_ID
I would use LEFT JOIN
Like this:
$sql = "SELECT `p`.`ID`,`p`.`post_title`,`p`.`post_category`,`p`.`post_perma`,`c`.`cat_ID`,`c`.`cat_nicename` FROM `".TBL_POSTS."` AS `p` ";
$sql .= "LEFT JOIN `".TBL_CATEGORIES."` AS `c` ON `c`.`cat_ID`=`p`.`post_category` WHERE `p`.`published`='1' AND `p`.`page`='0' ORDER BY `p`.`ID` DESC LIMIT 10";
You may need to tweak the WHERE clause to suite your needs more..
Please Note: This is one string, i have just split them onto two lines so it is easier to read. .= is to append the current string.

Categories