How to combine this two MySQL query using Group By - php

I have this table that i use to query by grouping via station_id.
+------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------+------+-----+---------+-------+
| id | varchar(50) | NO | PRI | NULL | |
| station_id | tinyint(3) | NO | | NULL | |
| game_type_id | smallint(1) | NO | MUL | NULL | |
| price | decimal(10,2) | YES | | 0.00 | |
| date_created | datetime | YES | MUL | NULL | |
| bet_no1 | tinyint(2) | YES | | 0 | |
| bet_no2 | tinyint(2) | YES | | 0 | |
+------------------+---------------+------+-----+---------+-------+
Here is the query i use to display it on a table using GROUP BY station_id
SELECT station_id,
COUNT(*) as bet_counts,
FORMAT(SUM(price),2) as gross
FROM bets
WHERE bet_void=0
AND date_created >= '2013-02-12 00:00:00'
AND date_created < '2013-02-23 00:00:00'
GROUP BY station_id
The query will give me.
+------------+------------+-------+
| station_id | bet_counts | gross |
+------------+------------+-------+
| 1 | 14 | 16.00 |
| 2 | 5 | 5.00 |
| 7 | 11 | 11.00 |
+------------+------------+-------+
But i also have another query that counts each specific bets( game_type_id ) from each station_id. I usually query this inside the a looping statement.
SELECT COUNT(*) as count
FROM bets
WHERE game_type_id = 1
AND station_id = {station_id from first query}
AND date_created >= '2013-02-12 00:00:00'
AND date_created < '2013-02-23 00:00:00'
My question is, how can i make this in one query and still use the GROUP BY station_id and also get the count of bets on each game_type_id? Something like this result.
+------------+------------+-------+-------------------------+-------------------------+
| station_id | bet_counts | gross | count_of_game_type_id_1 | count_of_game_type_id_2 |
+------------+------------+-------+-------------------------+-------------------------+
| 1 | 14 | 16.00 | 10 | 4 |
| 2 | 5 | 5.00 | 3 | 2 |
| 7 | 11 | 11.00 | 11 | 0 |
+------------+------------+-------+-------------------------+-------------------------+

You can do this by joining the results together. However, the logic in the two queries is very similar, so you can combine them into a single aggregation query:
SELECT station_id,sum(case when bet_void = 0 then 1 else 0 end) as bet_counts,
FORMAT(SUM(case when bet_void = 0 then price else 0 end),2) as gross,
sum(case when game_type_id = 1 then 1 else 0 end) as count
FROM bets b
where date_created >= '2013-02-12 00:00:00' AND date_created < '2013-02-23 00:00:00'
GROUP BY station_id

Related

MySql - Insert with IF and JOIN

I'm trying to add bonus points for users every 2 days. But I'm not sure how to join the users table and get the user_bonus value which indicates the last time a user received a bonus. Can this be done in one query?
Insert query:
INSERT INTO points_plus (user_id, points) VALUES (?,?);
This would be the 2 day interval which needs to be checked:
user_bonus <= NOW() - INTERVAL 2 DAY
users table(part of it)
+-------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| weekly_mail | datetime | YES | | NULL | |
| user_bonus | datetime | YES | | NULL | |
| join_date | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+--------------+------+-----+-------------------+-----------------------------+
points_plus table
+----+---------+--------+---------------------+
| id | user_id | points | date |
+----+---------+--------+---------------------+
| 18 | 13 | 300 | 2015-10-07 12:06:39 |
| 43 | 13 | 99 | 2015-10-18 14:16:50 |
| 45 | 13 | 103 | 2015-10-19 05:49:49 |
+----+---------+--------+---------------------+
You can try this.
INSERT INTO points_plus (user_id, points)
SELECT id, $points
FROM users
WHERE user_bonus <= NOW() - INTERVAL 2 DAY

How can I move MYSQL query to Laravel Eloquent subquery?

My query like this:
SELECT AVG(c.total) FROM (
SELECT COUNT(*) as total, b.`app_id` FROM (
SELECT DISTINCT `app_id`, `insurance_id`
FROM `application`
WHERE `price` IS NOT NULL AND `created_at` >= "2015-11-01 00:00:00"
GROUP BY `app_id`, `insurance_id`
) as b
GROUP BY b.`app_id`
) as c
How can I implement this query to Laravel Eloquent?
My table data is like this;
+------+--------+--------------+---------------+---------------------+
| id | app_id | insurance_id | price | created_at |
+------+--------+--------------+---------------+---------------------+
| 3867 | 33846 | 10 | NULL | 2015-11-20 17:50:26 |
| 3866 | 33846 | 4 | 642,42 | 2015-11-20 17:50:17 |
| 3865 | 33846 | 7 | 687.68 | 2015-11-20 17:50:02 |
| 3864 | 33846 | 8 | NULL | 2015-11-20 17:49:56 |
| 3863 | 33846 | 3 | 540.7500 | 2015-11-20 17:49:55 |
| 3862 | 33846 | 1 | 988.240000000 | 2015-11-20 17:49:54 |
| 3861 | 33846 | 2 | NULL | 2015-11-20 17:49:45 |
| 3860 | 33845 | 10 | 565.80 | 2015-11-20 17:22:25 |
| 3859 | 33845 | 4 | 504,90 | 2015-11-20 17:22:15 |
| 3858 | 33845 | 5 | 459.65 | 2015-11-20 17:22:04 |
| 3856 | 33845 | 7 | 664.58 | 2015-11-20 17:21:56 |
| 3857 | 33845 | 10 | 565.80 | 2015-11-20 17:21:56 |
| 3855 | 33845 | 8 | NULL | 2015-11-20 17:21:54 |
| 3854 | 33845 | 1 | 987.420000000 | 2015-11-20 17:21:48 |
| 3853 | 33845 | 3 | 518.6900 | 2015-11-20 17:21:47 |
| 3852 | 33845 | 2 | NULL | 2015-11-20 17:21:44 |
| 3851 | 33845 | 4 | NULL | 2015-11-20 17:21:31 |
| 3850 | 33845 | 7 | NULL | 2015-11-20 17:21:30 |
| 3849 | 33845 | 5 | 459.65 | 2015-11-20 17:21:26 |
| 3848 | 33845 | 3 | 518.6900 | 2015-11-20 17:21:23 |
+------+--------+--------------+---------------+---------------------+
I think the simplest solution will be to use the DB interface for this.
You could run the query like this:
$averages = \DB::select('SELECT AVG(c.total) FROM (
SELECT COUNT(*) as total, b.`app_id` FROM (
SELECT DISTINCT `app_id`, `insurance_id`
FROM `application`
WHERE `price` IS NOT NULL AND `created_at` >= "2015-11-01 00:00:00"
GROUP BY `app_id`, `insurance_id`
) as b
GROUP BY b.`app_id`
) as c');
You can take a look at what $averages looks like and what it contains and what methods are available for it using php artisan tinker which is a very useful tool for experimenting to find the solutions to problems.
If you want to set the created_at clause dynamically you can do something like this:
$dateString = '2015-10-15 00:00:00';
$averages = \DB::select('SELECT AVG(c.total) FROM (
SELECT COUNT(*) as total, b.`app_id` FROM (
SELECT DISTINCT `app_id`, `insurance_id`
FROM `application`
WHERE `price` IS NOT NULL AND `created_at` >= "?"
GROUP BY `app_id`, `insurance_id`
) as b
GROUP BY b.`app_id`
) as c', [$dateString]);
If you need the results of a query like this turned into a Model, look into Model#hyrdrate, you can even skip using DB and go straight to a model with Model#hydrateRaw, but since this query returns only one column that may not be what you're looking for.

force count to be zero in a mysql query

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.

Number of games a particular user has played today where there is no data

I'm trying to get the number of games that summoners in the queue have played today. I have tried several queries. The closest I have gotten is:
SELECT
s.summoner,
s.wins,
COUNT(*) as playedToday
FROM summoners s
LEFT JOIN teams_players tp ON tp.summoner_id = s.summoner
LEFT JOIN teams t ON t.id = tp.team_id
LEFT JOIN matches b ON t.id = b.blue_id
WHERE
b.played_on = DATE(NOW())
s.in_queue;
But that doesn't give the count per-user. It just gets the overall count.
None of the tables have any data on any of the summoners. What I'd like is something like:
+-----------------+------+-------------+
| summoner | wins | gamesPlayed |
+-----------------+------+-------------+
| DotAliscious | 353 | 0 |
| Kraator | 440 | 0 |
| Nammon | 667 | 0 |
| VictorousSecret | 843 | 0 |
| Canas | 544 | 0 |
| Sprognak | 502 | 0 |
| Ghostilocks | 808 | 0 |
| b0b d0e | 224 | 0 |
| Metroshica | 339 | 0 |
| RubenatorX | 478 | 0 |
+-----------------+------+-------------+
I can't think how to express this problem generically, which is why I haven't found a solution.
My data set. Note that teams.id matches up with matches.blue_id and matches.purple_id.
mysql> DESCRIBE summoners;
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| icon | int(11) | NO | | 0 | |
| summoner | varchar(32) | NO | UNI | NULL | |
| skype | varchar(32) | NO | | NULL | |
| email | varchar(32) | NO | | NULL | |
| in_queue | tinyint(1) | NO | | 0 | |
| wins | int(11) | NO | | 0 | |
| level | int(11) | NO | | 1 | |
| lan_wins | int(11) | NO | | 0 | |
| played_today | int(11) | NO | | 0 | |
+--------------+-------------+------+-----+---------+----------------+
10 rows in set (0.00 sec)
mysql> DESCRIBE matches;
+-----------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| blue_id | int(11) | NO | MUL | NULL | |
| purple_id | int(11) | NO | MUL | NULL | |
| status | varchar(32) | NO | | display | |
| played_on | datetime | NO | | 2012-04-06 13:53:55 | |
+-----------+-------------+------+-----+---------------------+----------------+
5 rows in set (0.00 sec)
mysql> DESCRIBE teams;
+---------+-------------+------+-----+------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| outcome | varchar(32) | NO | | incomplete | |
+---------+-------------+------+-----+------------+----------------+
2 rows in set (0.00 sec)
mysql> DESCRIBE teams_players;
+-------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| team_id | int(11) | NO | MUL | NULL | |
| summoner_id | int(11) | NO | MUL | NULL | |
+-------------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
You're going to want to use a subselect to get the count of records that meet the condition, and that will return you a 0 if the condition is false. Something along the lines of
(SELECT COUNT(*) FROM matches b WHERE b.blue_id = t.id AND b.played_on = DATE(NOW())) AS playedToday
and you will want to remove the LEFT JOIN to the matches table and the WHERE clause checking the date.
Your played_on is datetime and you are comparing it with date maybe that's your problem. YOu should try:
WHERE
DATE(b.played_on) = DATE(NOW())
Also what do you mean by s.in_queue? Did you forget the AND? Do you mean
WHERE
DATE(b.played_on) = DATE(NOW())
AND
s.in_queue;

mysql multi group query with count

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

Categories