Group data based on range in mysql - php

I have table products in my database. price column has various repeating values. I want to fetch count of products based on range 10-50, 51-100 and so on.
One way I could identify was to execute multiple queries on the database with different where clauses.
I was wondering if it could be done in one query itself.
what I tried was
$q = "SELECT count(*) FROM products WHERE price>10 AND price<50"
$q1 = "SELECT count(*) FROM products WHERE price>50 AND price<100"
Now this gives me the count of individual ranges, but I have to manually write queries for all the ranges.

select product_name,
count(case when price between 10 and 50 then 1 else null end) as `10-50 count`,
count(case when price between 51 and 100 then 1 else null end) as `51-100 count`
from products
group by product_name

Related

Select rows from 2 tables in 1 query

Need to select name,domain from table 1, than I need a sum of values from a column from table 2 with condition table1.id = table2.
Table 2 does not have the same number of columns.
I have tried joining 2 queries with UNION and UNION ALL, but i keep getting the same problem of different number of columns.
$rows = $test->query('select domain,name from customers
UNION
select SUM(customer_id) from main.rentals,main.customers where customer_id = customers.id');
Expected would be "User's Name" - "domain" - "number of rentals(integer)"
Warning: SQLite3::query(): Unable to prepare statement: 1, SELECTs to the left and right of UNION do not have the same number of result columns
If you use SUM, it will sum all ids, for example if you have a customer ID of 10 and it shows 5 times the result will be 50. In the other hand if you use count it will count the rows that that id was shown. That's why we are doing a group by. You may tweak it to fill your specific needs, but this is one way to achieve what you want.
$query = "
SELECT
domain,
name,
count(customer_id) as Total
FROM
customers
left join main.rentals on customers.id = customer_id
GROUP BY
customer_id
";
$test->query($query );

Explain a MySQLi query that displays top 3 sold cars

I found the following mysqli query on the internet. It displays top 3 sold cars
//create conection with mysql database.
$conn = mysqli_connect("localhost","root","","cars");
//query
$select = "SELECT ord.*, sum(amount) as amt from orders as ord GROUP BY id_car order by amt desc limit 0,3";
$data = mysqli_query($conn,$select);
This query works fine but I would like if anyone can explain me this first section of the query: SELECT ord.*,
It seems like "ord" refers to orders but is it the same as saying: SELECT * FROM orders??
See table in the screenshot image
orders table
In the query there is orders as ord this gives the orders table an 'alias' of the orders table, so ord.* means orders.*
It is a bit redundant in this query to be honest, mainly used if there are multiople tables in a query :)
For this query you can simply do:
$select = "SELECT *, sum(amount) as amt from orders GROUP BY id_car order by amt desc limit 0,3";
Let's break it down:
a) Select all fields from table named ord which will be defined in c)
SELECT ord.*,
b) Select sum of column amount and name it amt
sum(amount) as amt
c) Use table orders for the query and define an alias name ord for that table, see a)
from orders as ord
It is same as select * from tableName,it will fetch all columns from table.But alias Name is given for the table. Using alias Name is best practices for joining the multiple tables.
since you are using single table you can do this also.
SELECT *, sum(amount) as amt from orders as ord GROUP BY id_car order by amt desc limit 0,3

Need SQL query with good performance to select data that does NOT match criteria

I have a database with
a company table
a country table
a company_country n:n table which defines which company is available in which country
a product table (each product belongs to one specific categoryId)
and a company_product_country n:n:n table that defines which company offers which product in which country.
The latter has the three primary key columns companyId, productId, countryId and the additional columns val and limitedAvailability. val is an ENUM with the values yes|no|n/a, and limitedAvailability is an ENUM with the values 0|1.
Products within categories 1 or 2 are available in all countries and therefore get countryId = 0. But at the same time, only these very products may have a limitedAvailability = 1.
An SQLFiddle with a test database can be found here: http://www.sqlfiddle.com/#!9/a065a/1/0
It contains five countries, products and companies.
Background information on what I need to select from the database:
A PHP script generates a search form where an arbitrary list of countries and products can be selected. The products are separated by categories (I did not add the category table in the sample database, because it is not needed in this case). For the first category, I can select whether to exclude products with limited availability.
Generating the desired result works fine:
It displays all companies that are available in the selected countries and have at least one of the selected products available. The result offers a column that defines how many of the selected products are available by company.
If the user defines that one or more categories should not contain products with limited availability, then the products within the corresponding categories will not count as a match if the company offers them with limited availability only.
I am pleased with the performance of this query. My original database has got around 15 countries, 100 companies and 150 products. Selecting everything in the search form occupies the MySQL server for around two seconds which is acceptable for me.
The problem:
After generating the result list of companies which matches as many product search criteria as possible, I use PHP to iterate through those companies and run another SQL query that should give me the list of products that the company does not offer corresponding to the search criteria. The following is an example query for companyId 1 to find out which products are not available when
the desired products have the productIds 2, 4 and 5
the product's country availability should be at least one of the countryIds 1, 2 or 3
the product should not have a limitedAvailability when it is from categoryId = 2:
SELECT DISTINCT p.name
FROM `product` p
LEFT JOIN `company_product_country` cpc ON `p`.`productId` = `cpc`.`productId` AND `cpc`.`companyId` = 1
WHERE NOT EXISTS(
SELECT *
FROM company_product_country cpcTmp
WHERE `cpcTmp`.`companyId` = 1
AND cpcTmp.val = 'yes'
AND (
cpcTmp.limitedAvailability = 0
OR p.categoryId NOT IN(2)
)
AND cpcTmp.productId = p.productId
)
AND p.`productId` IN (2,4,5)
AND countryId IN(0,1,2,3);
The database along with this query can be found on the SQLFiddle linked above.
The query generates the correct result, but its performance dramatically decreases with the number of products. My local SQL server needs about 4 seconds per company when searching for 150 products in 15 countries. This is inaccpetable when iterating through 100 companies. Is there any way to improve this query, like avoiding the IN(...) function containing up to 150 products? Or should I maybe split the query into two like so:
First fetch the unmatched products that do not have country Id 0 and are IN the desired countryIds
Then fetch the unmatched products in countryId = 0 and if applicable filter limitedAvailability = 0
?
Your help is gladly appreciated!
I would suggest writing the query like this:
SELECT p.name
FROM product p
WHERE EXISTS (select 1
from company_product_country cpc
where p.productid = cpc.productid and
cpc.companyid = 1 and
cpc.countryid in (1, 2, 3)
) and
NOT EXISTS (select 1
from company_product_country cpcTmp
where cpcTmp.productId = p.productId and
cpcTmp.companyId = 1 and
cpcTmp.val = 'yes' and
cpcTmp.limitedAvailability = 0
) AND
NOT EXISTS (select 1
from company_product_country cpcTmp
where cpcTmp.productId = p.productId and
cpcTmp.companyId = 1 and
cpcTmp.val = 'yes' and
p.categoryId NOT IN (2)
)
p.`productId` IN (2, 4, 5) ;
Then, you want the following indexes:
product(productid, categoryid, name)
company_product_country(productid, companyid, countryid)
company_product_country(productid, companyid, val, limitedavailability)
company_product_country(productid, companyid, val, category)
Note: these indexes completely "cover" the query, meaning that all columns in the query come from the indexes. For most purposes, is probably sufficient to have a single index on company_product_country. Any of the three would do.
Take the query that identifies the products that match the user selection. Subquery it and outer join it to the products table. Exclude the matches.
SQL Fiddle
SELECT p.name
FROM
product p LEFT JOIN
(
SELECT productId
FROM company_product_country cpcTmp
WHERE companyId = 1 AND
countryId IN (0,1,2,3) AND
(
productId IN (4, 5) OR
(productId = 2 AND limitedAvailability = 0)
)
) t
ON p.productId = t.productId
WHERE
t.productId IS NULL AND
p.productId IN (2,4,5)

How to perform multiple table operations in mysql?

I just want to perform multiple table operations in single query. The query is:
select name,sno , id as ids ,(select sum(amount) from client_credits
where user_id = ids) As total from clients where sno = '4' and total > '0'
This query is not working when I am trying use ** total > 0 **. Is there any other possibility ways? Please help me.
total is an alias. Aliases are not resolved when the WHERE clause is reached.
Try: where sno = 4 having total > 0
Alternatively, and more efficiently:
SELECT `c`.`name`, `c`.`sno`, `c`.`id`, SUM(`ccr`.`amount`) AS `total`
FROM `clients` AS `c`
JOIN `client_credits` AS `ccr` ON `c`.`id`=`ccr`.`user_id`
WHERE `c`.`sno` = 4
GROUP BY `c`.`id`
Notice how the total > 0 part is gone? That's because if there are no rows to join, then nothing will be joined and the rows are removed from the result ;)

Mysql Join Two Queries

I have two queries:
SELECT opr, COUNT(*) FROM table WHERE field = 'YES' GROUP BY opr
SELECT opr, MAX(category) FROM table WHERE field = 'NO' GROUP BY opr
So basically in the first query I am getting the number of transactions a user makes.
In the second query I am getting a category that all of those transactions fall under. I don't want to get all categories for each transaction they made, just the Max of the category field so that I have one entry per operator.
Until now, I have been catching both result sets in separate arrays and the looping through both arrays to get the complete opr->picks->category.
This doesn't always work it sometimes associates the wrong category to the wrong operator.
Is there a way to combine these two queries into one, so that I get the operator and picks, then the MAX(category)? The issue is that the conditions for each query are different on the field column.
SELECT opr,
COUNT(CASE WHEN field = 'YES' THEN 1 END) AS number_of_transactions,
MAX(CASE WHEN field = 'NO' THEN category END) AS category
FROM table
GROUP BY opr ;
The above logic can be attained in one query by using CASE
SELECT opr, COUNT(CASE WHEN `field` = 'YES' THEN opr END) as `count`,
MAX(CASE WHEN `field` = 'NO' THEN category END) as `max`
FROM table GROUP BY opr
Just add it in:
SELECT opr,count(*), MAX(category) FROM table WHERE field = 'YES' GROUP BY opr
You might also be able to drop it from 2 queries to 1 with this:
SELECT opr,count(*), MAX(category), field FROM table GROUP BY opr, field
even faster on the processor, use a sum bool:
select
opr,
sum(field='yes') as transactions,
max(if(field='no',category, null)) as category
from table
group by opr

Categories