I currently have an Array in PHP with product numbers. Lets call that products.
In my database I have a table containing combinations of product numbers and the price that belongs to that product.
Problem: My Array can hold duplicate entries if for instance article #1 is ordered twice.
If I use a query like
SELECT SUM(price) FROM articles WHERE article_number IN (products)
the duplicate entry of 1 get discarded. The query I am looking for gives the sum of 10 + 10 + 12.5 + 9.95.
Is there a way to do this within MySQL?
As a clarification to my data:
products = [1, 1, 2, 3];
articles| article_number | price
__________________________________
| 1 | 10.0
| 2 | 12.5
| 3 | 9.95
Thank you :)
winmutt has a solid answer. However, if you don't have such a table to to join with then you could build your query like so:
select sum (p) from (
(select price as p from articles where article_number = 1)
union all
(select price as p from articles where article_number = 1)
union all
(select price as p from articles where article_number = 2)
union all
(select price as p from articles where article_number = 3)
) s
If your products were in a table you could do a simple JOIN:
SELECT SUM(price) FROM articles JOIN products on article_number=product_number
I thought there might be an easier way of doing this in SQL. I solved it in PHP by querying all the prices of the array's products and then in iterating over my Array in PHP to sum up the price there.
Related
I have a quite large products table and I need some smart solution to find out which products are (in woocommerce terms) Simple, Variable, and Variation.
In the example table below, ids 6 and 7 are Simple products (they don't have children), 1 and 4 are Variable products (they have children), and 2,3,5 are Variations (they are children).
id
item_id
parent_id
other_columns
1
aaa
aaa
...
2
aaa-1
aaa
...
3
aaa-2
aaa
...
4
bbb
bbb
...
5
bbb-1
bbb
...
6
ccc
ccc
...
7
ddd
ddd
...
My goal is to first get Simple products, then get Variable products and import them and lastly get Variations and import them to the existing parent Variable products.
I have a solution for Simple products:
SELECT *
FROM (
SELECT *
FROM $table_name
WHERE item_id = parent_id
GROUP BY parent_id
HAVING COUNT(*) = 1
) AS ONLY_ONCE
I've tried similar for the Variable products (count(*) > 1), but it doesn't work...
For Variation I have:
SELECT *
FROM $table_name
WHERE item_id != parent_id
Simple products - select all where item_id is equal with parent_id, and parent_id occurs only once.
Variable products - select all where item_id is equal with parent_id and parent_id occurs more than once.
Variation - select all where item_id and parent_id are not equal.
How could I write those three queries, especially the second one? any help is appreciated.
SELECT *,
CASE WHEN EXISTS ( SELECT NULL
FROM test t2
WHERE t2.parent_id = t1.item_id
AND t2.item_id <> t2.parent_id )
THEN 'Variable'
WHEN NOT EXISTS ( SELECT NULL
FROM test t3
WHERE t3.parent_id = t1.item_id )
THEN 'Variation'
ELSE 'Simple'
END Category
FROM test t1;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=b3215cbb3febbdbc4132ee00aac2ad8e
I would solve this as a combination of SQL queries and php code.
At first I would get all parents (variable products) and fetch the results. In PHP then loop through the results and use the parents id as parameter for the next query.
We require to get row if product_id is in sequence.
Table (product)
product_id name
1 Parle
2 Coconut
3 Pizza
4 Colgate
5 Ice Cream
6 Nuts
8 Britania
9 Pepsi
Require Output
product_id name
1 Parle
2 Coconut
3 Pizza
4 Colgate
5 Ice Cream
6 Nuts
product_id - 8 and 9 not getting because it is not in sequence.
My Try
select distinct t1.*, t1.product_id, (select GROUP_CONCAT(t2.product_id) from product as t2) as p_id
from product t1
having FIND_IN_SET(t1.product_id+1, p_id)
Output
product_id name
1 Parle
2 Coconut
3 Pizza
4 Colgate
5 Ice Cream
In this try i am not getting product_id - 6 row.
Note : I want MySql query not in PHP.
Thank You !
One way i can think of is to user user defined variable to get the rank of row and then calculate the difference of product id and rank and select only those rows where difference = 0
select *
from(
select f.*,#row:= #row + 1 rank,
product_id - #row as diff
from product f,
(select #row:= 0) t
order by product_id
) t1
where diff = 0
Demo
Or if you want to pick the least sequence no. automatically you can write it as
select *
from(
select f.*,#row:= #row + 1 rank,
product_id - #row as diff
from product f,
(select #row:= (select min(product_id) from product_sale_flag) a) t
order by product_id
) t1
where diff = -1
Demo
Explanation
First query assign's minimum value of product_id to variable #row,then it assigns a rank to each row ordered by product_id in ascending order, once rank is assigned for every row then it calculates the difference between the original value of product_id and lastly using the resultant difference it checks where difference is 0 get those rows because they follow the sequence. Hope this makes sense
I am still a php/mysql newbie and I am working on mysql table relationship concept and i am having an issue with using mysql count in multiple table. Here is my db structure.
**product table**
id product_name product_img groupeid
1 Sneaker Mark sneaker_adi.png 1
2 bag Eric bageric.png 2
3 Sneaker Etoi sneakeretoi.jpg 1
**groupe table**
group_id group_name
1 men
2 women
**category table**
catid catname
1 sneaker-shoes
2 bag-woman
**productcategory table**
prod_id cat_ID
1 1
2 2
3 1
What i want to do is to determine the number of sneaker-shoes using mysql.
We can see that the number of sneaker-shoes in the db is 2.
But how can i use **count()** in these multiple tables.
I tried like this;
$sql = "SELECT COUNT(*) product.id,product_name,catname FROM product INNER JOIN productcategory ON product.id = prod_id INNER JOIN category ON catid = cat_ID WHERE catname='sneaker-shoes'";
i got error like:
Fatal error: Call to a member function execute() on a non-object in C:\wamp\www\kbashopping\Homme\index.php on line 32
Hope i exposed the issue clearly, any help and assistance will be appreciate
Thanks
If you are looking only for the count, mention only the count phrase in the Select clause.
Change :
SELECT COUNT(*) product.id,product_name,catname FROM
to :
SELECT COUNT(product.id) FROM
SELECT count (pc.cat_ID) FROM productcategory pc inner join category c on c.catid = pc.cat_ID where c.catname = 'sneaker shoes';
This will build a temporary table in mysql that joins category and product category but only including results where the catname is sneaker shoes. Then it selects a column to run the count operation on, and returns the result of count.
In my database i have categories, offers and coupons. i would like to count offers and coupons that exist in each category. when i use union it returns the same category twice.
i have the below query that returning same category rows with same name. i try to use union distinct but it does not work.
(SELECT
cat1.id AS cat1id, cat1.title AS title,
count(offers.id) AS offercounter
FROM cat1
INNER JOIN offers
ON offers.category=cat1.title
GROUP BY cat1.id
order by cat1.order)
UNION
(SELECT
cat1.id AS cat1id, cat1.title AS title,
count(coupons.id) AS couponscounter
FROM cat1
INNER JOIN coupons
ON coupons.category=cat1.title
GROUP BY cat1.id
order by cat1.order)
the result
cat1id title offercounter
2 Food 5388
23 Clothes 6000(this is offers)
32 Technology 499
40 Clothes 4(this is coupons)
i would like clothes to be (offercounter + couponscounter).
example: clothes=6004 and not two different rows
the desired result would be :
cat1id title offercounter
2 Food 5388
23 Clothes 6004(offers+coupons)
32 Technology 499
Alternative avoiding unions or sub queries is to use a couple of LEFT OUTER JOINS, and count the distinct ids from each table:-
SELECT cat1.id AS cat1id,
cat1.title AS title,
COUNT(DISTINCT offers.id) + COUNT(DISTINCT coupons.id) AS offercounter
FROM cat1
LEFT OUTER JOIN offers ON offers.category = cat1.title
LEFT OUTER JOIN coupons ON coupons.category = cat1.title
GROUP BY cat1.id AS cat1id,
cat1.title AS title
EDIT
A left outer join will return a row of nulls when there is no matching row.
For example if there was a row on cat1 with a matching row on offers but no matching row on coupons then the resulting row would consist of the row from cat1, the row from offers and the fields from coupons would be null.
This SQL will get every combination of matching rows. So if you had:-
cat1 fields offers fields coupons fields
id title id category id category
1 fred 99 fred 77 fred
1 fred 99 fred 88 fred
1 fred 100 fred 77 fred
1 fred 100 fred 88 fred
2 burt 120 fred NULL NULL
2 burt 121 fred NULL NULL
Hence the count uses DISTINCT to only could each id within a category once. As COUNT(field name) only counts non null values, with this example data for the 2nd category the count from coupons will be 0.
Union returns distinct rows. Your returned rows are distinct indeed. What you need to do to get your desired result is aggregate after unioning.
select min(cat1id) as cat1id, title, sum(offercounter) as offercounter
from
(your_query) as subquery
group by title
replace your_query with your existing query
Why don't you simple sum up the offercounter and use group by with order by cat1id.
SELECT cat1id,title,sum(offercounter) as offercounter
FROM offers GROUP BY title ORDER BY cat1id
View : SQL Fiddle
Output :
cat1id title offercounter
2 Food 5388
23 Clothes 6004
32 Technology 499
May be this can help.
SELECT cat1.id AS cat1id, cat1.title AS title ,((SELECT COUNT(offers.id) FROM offers WHERE offers.category=cat1.title)+(SELECT COUNT(coupons.id) FROM coupons WHERE coupons.category=cat1.title)) AS offercounter
FROM cat1
I'd like to know the most efficient SQL query for achieving this problem:
Say we have a table with two columns, one storing entry ids (entry_id) and one storing category ids (cat_id):
entry_id cat_id
3 1
3 2
3 3
3 20
4 1
4 2
4 21
I'd like to count how many distinct entry_id's there are in the categories 1, 2 OR 3 but that also must be in cat_id 20.
For example, categories 1, 2 and 3 might represent music genres (Country, Pop etc.), while category 20 might be recording formats (CD, Vinyl etc.). So another way of putting it verbally could be: "How many products are there that are on Vinyl and in either the Pop or Country category?"
I could achieve this with a nested loop in code (PHP) or possibly with a nested SQL subquery, but neither feels that efficient. I feel there must be an obvious answer to this staring me in the face...
EDIT TO ADD:
I would also like to do this without modifying the database design, as it's a third party system.
FURTHER EXAMPLE TO CLARIFY:
Another real-world example of why I'd need this data:
Let's say the category ids instead represent either:
Accommodation Types (Camping = 20, Holiday Cottage = 21)
OR
Continents and their sub-regions (i.e. Europe = 1, UK = 2, England = 3)
Let's say someone has selected that they are interested in camping (cat_id = 1). Now we need to count how many camping products there are in the Europe. A product might be tagged as both Europe (parent), UK (child) AND England (grand-child), giving us an array of category ids 1, 2 or 3. So we now need to count how many distinct products there are in both those categories AND the original accommodation category of 1 (camping).
So having selected Camping, the end result might look something like:
Europe: 4 camping products
UK: 2 camping products
England : 1 camping product
Wales : 1 camping product
France: 2 camping products
etc.
Hope that helps...
I believe you want GROUP BY, COUNT() and EXISTS()
declare #t table(entry_id int, cat_id int)
insert #t select 1, 1
insert #t select 2, 1
insert #t select 1, 2
insert #t select 2, 2
insert #t select 3, 1
insert #t select 1, 20
select t1.cat_id, COUNT(*)
from #t as t1
where exists(
select * from #t
where t1.entry_id = entry_id
and cat_id = 20)
group by t1.cat_id
V2 using join instead of EXISTS()
declare #t table(entry_id int, cat_id int)
insert #t select 1, 1
insert #t select 2, 1
insert #t select 1, 2
insert #t select 2, 2
insert #t select 3, 1
insert #t select 1, 20
select t1.cat_id, COUNT(*)
from #t as t1
join #t as t2 on t1.entry_id = t2.entry_id and t2.cat_id = 20
group by t1.cat_id
select count(distinct entry_id) from myTable where cat_id=20 and entry_id in
(select distinct entry_id from myTable where cat_id in (1,2,3));
With no subqueries, using JOIN and GROUP BY:
Join the table to itself using entry_id (this gives you all possible pairs of cat_id for that entry_id). Select rows having cat_id both a member of (1,2,3) and the second cat_id = 20.
SELECT r1.entry_id
FROM records r1
JOIN records r2 USING(entry_id)
WHERE r1.cat_id IN (1,2,3)
AND r2.cat_id = 20 GROUP BY entry_id;