MySQL associated table COUNT() and GROUP BY - php

I am doing a pretty normal routine, but having a tough time getting my output correct.
I have two tables: *ads_list* (listings) and *ads_cate* (categories).
I am currently displaying my category list like so:
SELECT id, cateName FROM ads_cate ORDER BY cateName
What I am trying to achieve: count of all items in each category in this format:
Category | Number of Ads
categoryName 56
This is my current code, and have been tweaking but getting no output in my array:
SELECT
ads_cate.id,
ads_cate.cateName, // Category Name
ads_list.id,
ads_list.COUNT(title), // Title of ad
ads_list.Category // Relational Category ID INT(11)
FROM
ads_cate,
ads_list
GROUP BY cateName
ORDER BY cateName
I am calling in all required fields and running a COUNT() on my title field (as these are unique for each ad) and then I am grouping by cateName which also seems correct.

See what this gives you. I think it is what you need.
SELECT
ads_cate.cateName, // Category Name
COUNT(ads_list.id), // Title of ad
FROM
ads_cate
INNER JOIN
ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
ORDER BY cateName

Related

how to fetch data from 2 different tables by comparing values of their fields

I have 2 tables for products what I need to do is, get product's name and description on basis of their attributes i.e. If table1's product's attribute1 is same as table2's product attribute1 then fetch product name and description of both the table. I'm litile confused with query, can somebody please help.
Here is my query:
select Product_Article_Number, Product_Description, Comments,
from P_Products as pp
WHERE EXISTS(select * from Competitor_Products as cc
WHERE(cc.CAttribute1 = pp.Attribute1
AND cc.CAttribute2 = pp.Attribute2
AND cc.CAttribute3 = pp.Attribute3
AND cc.CAttribute4 = pp.Attribute4))
result:
by this I'm getting details for table1 only, how to get other tables detail too.

SELECT DISTINCT multiple values from a single cell

Let's say I have the following table, called test:
Executing the query SELECT DISTINCT category FROM test ORDER BY category; will output:
When changing a value as follows:
…and calling the query SELECT DISTINCT category FROM test ORDER BY category; again, I'll get:
But I want to get the following instead:
Is there a way to do this in SQL? Or should I do this directly in my PHP?
You should have 3 tables here. One will hold the the categories, the other one will hold the items and the final one will hold the relations between categories and items (it is also known as associative table):
categories: id name
items: id name
categories_items: category_id item_id
Your query in this case will become:
SELECT id, name
FROM categories
ORDER BY name;
If you want to get all items from a category you could do:
SELECT id, name
FROM items
JOIN categories_items
ON items.id = categories_items.item_id
AND categories_items.category_id = 4;
You should definetely normalize your tables but if you still insist on this table structure, you can try this query:
WITH CatChar(aChar, remain) AS (
SELECT LEFT(category,1), RIGHT(category, LEN(category)-1)
FROM test WHERE LEN(category)>0
UNION ALL
SELECT LEFT(remain,1), RIGHT(remain, LEN(remain)-1) FROM CatChar
WHERE LEN(remain)>0
)
SELECT DISTINCT aChar FROM CatChar
(Assuming your all category names are just one char length, otherwise you should reorganeze LEFT(...) part to split according to your separator)

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)

Join a table only where there is a count in the subquery

I'm making a search engine in which a page visitor can search for music artists based on 4 different attributes which the artists will have a rating of from 0- 100 and by entering the minimum value of a specified attribute, the visitor can view the list of artists with ratings greater than or equal to the desired value. After the query I have the fetch array and foreach statement already set but I am having trouble with the query.
I've tried the following query statement. It's one cohesive statement:
SELECT users.username, databaseimage.profile
// users.username is artists username
// databaseimage is table where profile pic is stored
FROM users
JOIN databaseimage ON users.id = databaseimage.user_id
JOIN attributes ON users.id = attributes.userid
// user.id, database.user_id, and attribute.userid all correspond to the id of a specified artist
// attributes is table where attributes are stored
The above gets me all the data that I need. Below is the part I need help with. I want to narrow the data down such that only the data corresponding to artists with attribute ratings (as attr) greater than $selectnumber (Number specified by the visitor) is in the the result array. This what I have tried.
WHERE attribute.userid
HAVING COUNT() IN (
SELECT userid, ($attribute DIV TotalRatingEntries) as attr
FROM attributes
WHERE attr >= '$selectnumber'
)
A far as I understand data structure I can propose the query below:
SELECT
users.username,
databaseimage.profile
FROM
users
JOIN databaseimage ON users.id = databaseimage.user_id
JOIN attributes ON users.id = attributes.userid
WHERE
attribute.userid IN
(
SELECT
userid
FROM
attributes
group by
userid,TotalRatingEntries
having
sum(attribute)/TotalRatingEntries >= '$selectnumber'
)
Please provide more details about these 3 tables, maybe I misunderstood something.

Group by ID and Show all results from mysql

I have 2 tables
tabcats - Cat_Id, Cat_Name
tabnews - News_Id, News_Name, Cat_Id
So I'm trying to make a select on database and return all results but using
Group by Cat_Id
so my results was supposed to be
let's say I have 3 Categories and 5 News
Results
Cat_Name 1
News_Name (1)
News_Name (2)
Cat_Name 2
News_Name (3)
News_Name (4)
Cat_Name 3
News_Name (5)
I read something about using LEFT OUTER JOIN but I don't get this clearly.
First you need to be clear about yourself. What I supposed that you tried to do is select some counts of latest news,isn't it? Try query similar to this one: The below query Find the course ID, semester, year and title of each course offered by the Comp. Sci. department
select section.course_id, semester, year, title from section, course where section.course_id = course.course_id and dept_name = ‘Comp. Sci.'
Ordering can be done as follows:
return(mysql_query("SELECT * FROM tabNews GROUP BY news_id DESC LIMIT *counts*"));
This is to list all news together with cat name sorting by cat name follow by news name.
SELECT News_Name,Cat_name from tabNews n left join tabCat c on n.cat_id=c.cat_id
ORDER BY c.cat_name,n.news_name

Categories