table milestoneeventI have three tables file and milestone event. I want to count milestones but by Company.
For example, if I want to count number of last milestone added for the milestone id=1, I do this:
select count('id') as st
from (
select idfile,
max(idmilestone) as max_idmilestone
from milestoneevent
group by idfile)
d where max_idmilestone =1
my problem is how to count them but for each company in table file I have column company. See the picture for more details
Statement should look like this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
GROUP BY idfile, Comp
) d GROUP BY d.max_idmilestone, d.Comp
In the subquery it give you the max(idmilestone) for every company but only if one milestone exists for a idfile, than count how many a max_idmilestone is occuring.
The Result of my test is
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
| Oracle | 1 | 1 |
| Microsoft | 2 | 2 |
| Oracle | 1 | 2 |
+-----------+----------+---+
**Query for Company or milestoneid
If you want to query for Company or max_idmilestone just do this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
WHERE Comp = "Microsoft"
GROUP BY idfile, Comp
) d
WHERE d.max_idmilestone = 1
GROUP BY d.max_idmilestone, d.Comp
Output
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
+-----------+----------+---+
For My Test I used the following structure. Skipped some columns which are not necessary for the test
CREATE TABLE `milestoneevent` (
`id` INT(22) NOT NULL auto_increment,
`idfile` INT(64) NOT NULL,
`idmilestone` INT(64) NOT NULL,
`company` VARCHAR(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `file` (
`id` int(22) NOT NULL AUTO_INCREMENT,
`Comp` varchar(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
Data of the test
+----+--------+-------------+
| id | idfile | idmilestone |
+----+--------+-------------+
| 1 | 1 | 1 |
| 2 | 10 | 1 |
| 3 | 11 | 1 |
| 4 | 12 | 1 |
| 5 | 13 | 1 |
| 6 | 14 | 1 |
| 7 | 15 | 1 |
| 8 | 16 | 2 |
| 9 | 14 | 2 |
| 10 | 18 | 2 |
+----+--------+-------------+
+----+-----------+
| id | Comp |
+----+-----------+
| 1 | Microsoft |
| 10 | Microsoft |
| 11 | Microsoft |
| 12 | Microsoft |
| 13 | Microsoft |
| 14 | Microsoft |
| 15 | Oracle |
| 16 | Oracle |
| 18 | Microsoft |
+----+-----------+
Related
So I normalize my database and it seems quite complicated for me to fetch or update records in tables.
I have 5 tables ( details, country, materials, vendor_countries, vendor_materials). Actually "details" is my main table.
country table have two column (id, name).
materials table also have two column(id, name).
details table have personnel information about vendors (name, email, phone, address).
A vendor could have multiple countries and materials so I made two more tables vendor_countries and vendor_materials and their column are (did,cid), (did,mid).
"did" is the id of each vendor coming from details table and cid,mid is the country id and material id coming from country and material table.
Now I want to fetch vendors along with their countries and materials.
here is my details table, vendor_countries and vendor_materials tables
so far I made a query which is shown below:
select dt.vendor,
dt.email,
dt.address,
c.country,
m.material,
c.country
from country c
inner join vendor_countries vc on (c.id = vc.cid)
right join details dt on (dt.id = vc.did)
left join vendor_materials vm on dt.id = vm.did
left join material m on vm.mid = m.id
and i am getting results like this:
which is not right it should be in 3 rows because "ali" vendor works in 3 countries and 3 materials. I am looking for some smart solution which also not slow down my page. Thanks in advance.
In the absence of any response regarding table schema I tried to re-create the tables based upon the descriptions above -prefixing each table with v_ so I could group the tables in this db and referencing did as vid ( vendor id ) and populating with what I believed to be the sample data from the question
mysql> describe v_country;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_details;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vendor | varchar(50) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
| phone | varchar(50) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
+---------+------------------+------+-----+---------+----------------+
mysql> describe v_materials;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_vendor_materials;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vid | int(10) unsigned | NO | MUL | 0 | |
| mid | int(10) unsigned | NO | MUL | 0 | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_vendor_countries;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vid | int(10) unsigned | NO | MUL | 0 | |
| mid | int(10) unsigned | NO | MUL | 0 | |
+-------+------------------+------+-----+---------+----------------+
mysql> select * from v_country;
+----+----------+
| id | name |
+----+----------+
| 1 | pakistan |
| 2 | India |
| 3 | Iran |
+----+----------+
mysql> select * from v_details;
+----+--------+------------------+---------------+-----------+
| id | vendor | email | phone | address |
+----+--------+------------------+---------------+-----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere |
+----+--------+------------------+---------------+-----------+
mysql> select * from v_materials;
+----+---------+
| id | name |
+----+---------+
| 1 | ceramic |
| 2 | iron |
| 3 | plastic |
+----+---------+
mysql> select * from v_vendor_materials;
+----+-----+-----+
| id | vid | mid |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+-----+-----+
mysql> select * from v_vendor_countries;
+----+-----+-----+
| id | vid | mid |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+-----+-----+
mysql> select * from v_details d
left outer join v_vendor_materials vm on vm.vid=d.id
left outer join v_vendor_countries vc on vc.vid=d.id
left outer join v_materials m on m.id=vm.id
left outer join v_country c on c.id=vc.id;
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
| id | vendor | email | phone | address | id | vid | mid | id | vid | mid | id | name | id | name |
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ceramic | 1 | pakistan |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere | 2 | 2 | 2 | 2 | 2 | 2 | 2 | iron | 2 | India |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere | 3 | 3 | 3 | 3 | 3 | 3 | 3 | plastic | 3 | Iran |
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
or, a more selective query
select
d.`id` as `vid`,
d.`vendor`,
d.`email`,
d.`phone`,
d.`address`,
m.`name` as `material`,
c.`name` as `country`
from v_details d
left outer join v_vendor_materials vm on vm.vid=d.id
left outer join v_vendor_countries vc on vc.vid=d.id
left outer join v_materials m on m.id=vm.id
left outer join v_country c on c.id=vc.id;
+-----+--------+------------------+---------------+-----------+----------+----------+
| vid | vendor | email | phone | address | material | country |
+-----+--------+------------------+---------------+-----------+----------+----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere | ceramic | pakistan |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere | iron | India |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere | plastic | Iran |
+-----+--------+------------------+---------------+-----------+----------+----------+
I have 2 tables in my demos database, in which I join them based on 2 keys, here I would like to count distinct of matched result,
my first table
MariaDB [demos]> select * from main_info;
+------+------+-------+-------+----------+
| key1 | key2 | info1 | info2 | date |
+------+------+-------+-------+----------+
| 1 | 1 | 15 | 90 | 20120501 |
| 1 | 2 | 14 | 92 | 20120601 |
| 1 | 3 | 15 | 82 | 20120801 |
| 2 | 1 | 17 | 90 | 20130302 |
| 2 | 2 | 16 | 88 | 20130601 |
+------+------+-------+-------+----------+
5 rows in set (0.00 sec)
And my second table
MariaDB [demos]> select * from product1;
+------+------+--------+--------------+
| key1 | key2 | serial | product_data |
+------+------+--------+--------------+
| 1 | 1 | 0 | NaN |
| 1 | 1 | 1 | NaN |
| 1 | 1 | 2 | NaN |
| 1 | 1 | 3 | NaN |
| 1 | 2 | 0 | 12.556 |
| 1 | 2 | 1 | 13.335 |
| 1 | 3 | 1 | NaN |
| 1 | 3 | 2 | 13.556 |
| 1 | 3 | 3 | 14.556 |
| 2 | 1 | 0 | 12.556 |
| 2 | 1 | 1 | 13.553 |
| 2 | 1 | 2 | NaN |
+------+------+--------+--------------+
12 rows in set (0.00 sec)
So distinct count of field serial is as follows, where serial is not zero
MariaDB [demos]> select count(distinct a.key1,a.key2) as serial_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.serial !=0;
+--------------+
| serial_count |
+--------------+
| 4 |
+--------------+
1 row in set (0.00 sec)
and distinct count of field product_data is as follows where product_data is not NaN
MariaDB [demos]> select count(distinct a.key1,a.key2) as product_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.product_data !='NaN';
+---------------+
| product_count |
+---------------+
| 3 |
+---------------+
1 row in set (0.00 sec)
In my original application I have many columns in my table, finally I would like to get result like below using single query, at present I am doing multiple query using PHP which is taking long time because for example if I have 100 columns, I have to execute function 100 times like above, so please someone guide me to speed up my application
+--------------+---------------+
| serial_count |product_count |
+--------------+---------------+
| 4 | 3 |
+--------------+---------------+
Below is structure of tables
DROP TABLE IF EXISTS `main_info`;
CREATE TABLE `main_info` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`info1` int(11) NOT NULL,
`info2` int(11) NOT NULL,
`date` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `main_info` WRITE;
INSERT INTO `main_info` VALUES (1,1,15,90,20120501),(1,2,14,92,20120601),(1,3,15,82,20120801),(2,1,17,90,20130302),(2,2,16,88,20130601);
UNLOCK TABLES;
DROP TABLE IF EXISTS `product1`;
CREATE TABLE `product1` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`serial` int(11) NOT NULL,
`product_data` varchar(1000) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `product1` WRITE;
INSERT INTO `product1` VALUES (1,1,0,'NaN'),(1,1,1,'NaN'),(1,1,2,'NaN'),(1,1,3,'NaN'),(1,2,0,'12.556'),(1,2,1,'13.335'),(1,3,1,'NaN'),(1,3,2,'13.556'),(1,3,3,'14.556'),(2,1,0,'12.556'),(2,1,1,'13.553'),(2,1,2,'NaN');
UNLOCK TABLES;
I didn't understand this why datetype changed, if I run on terminal
$ mysql -u root -p demos -e 'select key1,if(key1 !=0,key1,999.999) as `test1` from main_info'
Enter password:
+------+-------+
| key1 | test1 |
+------+-------+
| 1 | 1.000 |
| 1 | 1.000 |
| 1 | 1.000 |
| 2 | 2.000 |
| 2 | 2.000 |
+------+-------+
I expect it should be integer if IF condition is true
You can do it in a single query using conditional aggregation:
select count(distinct if(b.product_data !='NaN',a.key1, null),
if(b.product_data !='NaN',a.key2, null)) as product_count,
count(distinct if(b.serial !=0,a.key1, null),
if(b.serial !=0,a.key2, null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2
Output:
product_count serial_count
-----------------------------
3 4
Demo here
Edit: Credit goes to #Paul Spiegel
The query can be simplified using CONCAT:
select count(distinct if(b.product_data !='NaN',
CONCAT(a.key1, ',', a.key2),
null)) as product_count,
count(distinct if(b.serial !=0,
CONCAT(a.key1, ',', a.key2),
null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2
I have two tables t1, t2 and the following query:
SELECT t2.year,
Count(t1.id) AS count
FROM t1,
t2
WHERE t2.t1id = t1.id
AND t2.year IN ( 1995, 1996, 1997, 1998,
1999, 2000 )
GROUP BY t2.year
ORDER BY t1.year
Which results in:
+----------+--------+
| year | count |
+----------+--------+
| 1995 | 1 |
| 1998 | 3 |
| 1999 | 3 |
| 2000 | 28 |
+----------+--------+
And as you can see some years are missing. Is it possible to rewrite this query such that it results in?
+----------+--------+
| year | count |
+----------+--------+
| 1995 | 1 |
| 1996 | 0 |
| 1997 | 0 |
| 1998 | 3 |
| 1999 | 3 |
| 2000 | 28 |
+----------+--------+
I could use php and check which rows are missing to fill in the missing gaps, but that doesn't seem very efficient.. Any ideas?
edit
t1
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(128) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
t2
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| t1id | int(11) | NO | | NULL | |
| year | int(11) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
For example:
t1
+----------+---------+
| id | name |
+----------+---------+
| 1 | john |
| 2 | bob |
| .. | .. |
+----------+---------+
t2
+----------+---------+---------+
| id | t1id | year |
+----------+---------+---------+
| 100 | 1 | 1995 |
| 101 | 2 | 1998 |
| 103 | 3 | 1998 |
| .. | .. | .. |
+----------+---------+---------+
Where after the combination I end up with:
+----------+---------+
| id | year |
+----------+---------+
| 100 | 1995 |
| 101 | 1998 |
| 103 | 1998 |
| .. | .. |
+----------+---------+
SELECT t2.year,
IF(Count(t1.id) > 0, Count(t1.id), 0)
FROM t1,
t2
WHERE t2.t1id = t1.id
AND t2.year IN ( 1995, 1996, 1997, 1998,
1999, 2000 )
GROUP BY t2.year
ORDER BY t1.year
Without a source of all possible years that your query could cover you are going to have to use php to do this. One approach would could look something like this.
function getCountsForRange(\PDO $dbConn, $startYear, $endYear){
$ret = array_fill_keys(range($startYear, $endYear), 0);
$stmt = $dbConn->prepare("SELECT t2.year,Count(t1.id) AS count ".
"FROM t1,t2 ".
"WHERE t2.t1id = t1.id AND t2.year between ? and ? ".
"GROUP BY t2.year ORDER BY t1.year");
$stmt->execute([$startYear, $endYear]);
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)){
$ret[$row["year"]] = $row["count"];
}
return $ret;
}
create table yrCheat
( year int not null
);
create table t1
( -- forgive lack of PK
id int not null,
name varchar(128) not null
);
create table t2
( -- forgive lack of PK
id int not null,
t1id int not null,
year int not null
);
insert t1(id,name) values (100,'john'),(101,'bob'),(102,'sally');
insert t2(id,t1id,year) values (100,1,1995),(101,2,1998),(101,3,1998),(101,4,1998);
insert into yrCheat (year) values (1990),(1991),(1992),(1993),(1994),(1995),(1996),(1997),(1998),(1999),(2000);
-- etc
select yc.year,count(t1.id) as count
from yrCheat yc
left join t2
on t2.year=yc.year -- and yc.year in (1995,1996,1997,1998,1999,2000)
left join t1
on t1.id=t2.id
where yc.year in (1995,1996,1997,1998,1999,2000)
group by yc.year
order by yc.year
+------+-------+
| year | count |
+------+-------+
| 1995 | 1 |
| 1996 | 0 |
| 1997 | 0 |
| 1998 | 3 |
| 1999 | 0 |
| 2000 | 0 |
+------+-------+
6 rows in set (0.00 sec)
You will need to handle the empty rows pragmatically or in the query itself depending on the situation.
See:
MySQL GROUP BY and Fill Empty Rows
or
Populating query results with empty rows
For some ideas.
I have a MySQL database storing persons and their associated characteristics.
person table:
+----+--------+
| id | name |
+----+--------+
| 1 | Bella |
| 2 | Jacob |
| 3 | Edward |
| 4 | Renée |
| 5 | Alice |
+----+--------+
feature table:
+----+----------+
| id | name |
+----+----------+
| 1 | Bravery |
| 2 | Shyness |
| 3 | Kindness |
| 4 | Madness |
+----+----------+
person_features table:
+-----------+------------+-------+
| person_id | feature_id | value |
+-----------+------------+-------+
| 1 | 1 | 50 |
| 1 | 2 | 84 |
| 1 | 4 | 10 |
| 2 | 1 | 8 |
| 2 | 2 | 78 |
| 2 | 4 | 41 |
| 3 | 3 | 27 |
| 4 | 1 | 36 |
| 4 | 3 | 64 |
| 5 | 2 | 78 |
| 5 | 3 | 2 |
+-----------+------------+-------+
Let's say I want the list of all the persons ordered by descending shyness, kindness and
bravery (with the value of these features for each person):
+--------+---------+----------+---------+
| person | Shyness | Kindness | Bravery |
+--------+---------+----------+---------+
| Bella | 84 | NULL | 50 |
| Alice | 78 | 2 | NULL |
| Jacob | 78 | NULL | 8 |
| Renée | NULL | 64 | 36 |
| Edward | NULL | 27 | NULL |
+--------+---------+----------+---------+
I currently use this dynamically generated query:
SELECT person.name, pf2.value, pf3.value, pf1.value
FROM person
LEFT JOIN person_features pf2 ON person.id = pf2.person_id AND pf2.feature_id = 2
LEFT JOIN person_features pf3 ON person.id = pf3.person_id AND pf3.feature_id = 3
LEFT JOIN person_features pf1 ON person.id = pf1.person_id AND pf1.feature_id = 1
ORDER BY pf2.value DESC, pf3.value DESC, pf1.value DESC, person.name;
But it's a little slow with many features, because I must add a left join for each one. So, is there a way to use a more universal static query instead of a dynamic one? Even if it means a post-processing treatment in my PHP script to regroup data.
CREATE statements:
CREATE TABLE `feature` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
CREATE TABLE `person_features` (
`person_id` int(11) NOT NULL,
`feature_id` int(11) NOT NULL,
`value` int(11) NOT NULL,
PRIMARY KEY (`person_id`,`feature_id`),
KEY `feature_id` (`feature_id`),
CONSTRAINT `person_features_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`),
CONSTRAINT `person_features_ibfk_2` FOREIGN KEY (`feature_id`) REFERENCES `feature` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Result of EXPLAIN:
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| 1 | SIMPLE | person | ALL | NULL | NULL | NULL | NULL | 5 | Using temporary; Using filesort |
| 1 | SIMPLE | pf2 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
| 1 | SIMPLE | pf3 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
| 1 | SIMPLE | pf1 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
I'm not sure if this would be faster, but you can try using conditional aggregation:
select p.name,
max(case when pf.feature_id = 2 then value end) as shyness,
max(case when pf.feature_id = 3 then value end) as kindness,
max(case when pf.feature_id = 1 then value end) as bravery
from person p join
person_features pf
on p.person_id = pf.person_id
group by p.name
order by shyness desc, kindess desc, bravery desc;
Also, an index on person_features(person_id, feature_id, value) would speed up your query (as well as this one).
I have this query
SELECT
products_list.id_cat_unique,
products_categories_list.*,
COUNT(products_list.id_cat_unique) as counter
FROM products_categories_ids
LEFT JOIN products_list
ON products_categories_ids.id_cat_unique = products_list.id_cat_unique
LEFT JOIN products_categories_list
ON products_categories_list.id_cat_unique = products_categories_ids.id_cat_unique
GROUP BY products_categories_list.name_cat
ORDER BY products_categories_list.name_cat ASC
This is complicated to explain without having the tables on your screen but I'll try
what I want is count all the rows from products_list that can be associated with max two rows per id_cat_unique (contained in products_categories_list) that are English or Italian. This two items each could have infinite id_products in products_list of course.
I want the result to be grouped by products_categories_list.name_cat and by the language.
What I get with this query is categories grouped by name/unique id which is correct, the problem is that the counter value for both English and Italian turns out as the sum of all the products associated with one id_cat_unique regardless of the language. So if I have 12 rows from one category in English and 3 for the same category in Spanish I get 15 as counter for both the languages.
EDIT ADDING TABLES STRUCTURES
products_list
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id_product | int(11) | NO | PRI | NULL | auto_increment |
| id_product_unique | int(5) | NO | | NULL | |
| lang | varchar(2) | NO | | NULL | |
| name_product | varchar(200) | NO | | NULL | |
| desc_product | text | NO | | NULL | |
| id_cat_unique | int(2) | NO | | NULL | |
| status | int(1) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)
products_categories_ids
+---------------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------+------+-----+---------+----------------+
| id_cat_unique | int(5) | NO | PRI | NULL | auto_increment |
+---------------+--------+------+-----+---------+----------------+
1 row in set (0.00 sec)
products_categories_list
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id_cat | int(5) | NO | PRI | NULL | auto_increment |
| id_cat_unique | int(2) | NO | | NULL | |
| lang | varchar(2) | NO | | NULL | |
| name_cat | varchar(500) | NO | | NULL | |
| date_created | int(11) | NO | | NULL | |
| date_modified | int(11) | NO | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
result from query
| id_cat_unique | id_cat | id_cat_unique | lang | name_cat | date_created | date_modified | counter |
+---------------+--------+---------------+------+--------------------------------+--------------+---------------+---------+
| 1 | 18 | 1 | it | Carne di suino | 1308267538 | 1308267538 | 6 |
| 14 | 21 | 14 | it | Guanciali | 1308777322 | 1308777322 | 2 |
| 3 | 20 | 3 | it | Pollo a pezzi | 1308267892 | 1308267892 | 2 |
| 1 | 22 | 1 | en | Pork meat | 1308267538 | 1312383232 | 6 |
| 14 | 23 | 14 | en | Sheeps | 1308777322 | 1312383220 | 2 |
| 2 | 19 | 2 | it | That's a "test" | 1308267538 | 1308267538 | 7 |
+---------------+--------+---------------+------+--------------------------------+--------------+---------------+---------+
6 rows in set (0.00 sec)
"Pork meat" and "Carne di Suino" have respectively 1 and 5 products (from the same category but different language, i wanna group the counting by language too) instead it shows 6 for both
NEW question
I'd like to use this query for many purposes without using different things, so accordingly if I want to retrieve the categories with ONE language I'd add one where clause
select pcl.*,
(select count(*) from products_list pl
where pcl.id_cat_unique = pl.id_cat_unique
and pcl.lang = pl.lang) as counter
from products_categories_list pcl
where products_list.lang = 'en' <- added
ORDER BY pcl.name_cat ASC
I get Unknown column 'products_list.lang' in 'where clause'. Why?
I THINK this will work, if not, it's going to be close, let me know what you get, and I can modify it. I've modified the query around. Would this work?
select pcl.*,
(select count(*) from products_list pl
where pcl.id_cat_unique = pl.id_cat_unique
and pcl.lang = pl.lang) as counter
from products_categories_list pcl
ORDER BY pcl.name_cat ASC
The PCL and PL are just aliases for the tables, so I didn't have to always write out products_categories_list and products_list. You specify the alias in the from part of the statement, so from products_list pl allows you to refer to products_list as pl in the rest of the query.
The idea behind this is that you have a unique row for each products_categories_list and you want a count of a secondary table. This could have been done by group by or by a sub query. I put the correlated subquery in to count the number of rows in products_list that matched the products_categories_list and language, since you are getting all the columns out of the products_categories_list. The correlated subquery allows you to get a single value (count(*)) from a nested query.
Probably this: add DISTINCT
COUNT(DISTINCT products_list.id_cat_unique) as counter
This will ignore duplicate, so the 12+3 via the JOIN becomes 1+1