MySQL query for each subgroup - mysql

I have a table like this:
Year Month Code
1850 January 5210
1850 February 3524
1851 January 6752
1851 January 9877
1851 February 3698
I want to delete repeated months within a year (e.g. 1851 January). I donĀ“t mind loosing one code (6752 or 9877). I thought of using:
Select * from table1 group by Month
But I need to group for each year. Otherwise I will select only one January from the three in the table, and I need to select two of them (one in 1850 and one in 1851).
Of course my table is huge and I cannot do it manually. Thanks.

If you want to have only the entries with count>1 then you can do this:
Select year, month, code, count(1) as cnt from table1 group by year, month having cnt>1;
If the table is huge, make sure that both year and month are indexes, otherwise you'll spend lot of time waiting for results.
http://sqlfiddle.com/#!2/eb325/3
UPDATE: for the case where there are more than 2 rows (and actually in general, if you don't care about the lost "code" entries), it might make sense to select one entry from each year-month into a new table (which will leave you with unique year-month combinations) and then discard the old table, like that:
CREATE TABLE table1_temp SELECT year, month, MIN(code) as code FROM table1 GROUP BY year, month;
DROP TABLE table1;
RENAME TABLE table1_temp TO table1;
http://sqlfiddle.com/#!2/113954/1

Query suggested by #Ashalynd will work if you have only 2 duplicate rows but it will not work if you have 3 rows for year 1951 and month January ...Below query will take care it. You can remove all rows getting from below query.
SELECT
DISTINCT b.CODE
FROM
(SELECT YEAR, MONTH, CODE, COUNT(1) AS cnt FROM table1 GROUP BY YEAR, MONTH HAVING cnt>1) a,
table1 b
WHERE a.year=b.year AND a.month=b.month AND a.code<>b.code;
Another approach can be AS per below-
CREATE TABLE table1_new LIKE table1;ALTER TABLE table1_new ADD UNIQUE KEY (YEAR,MONTH);INSERT IGNORE INTO table1_new SELECT * FROM table1;
TRUNCATE TABLE table1;INSERT INTO table1 SELECT * FROM table1_new;
DROP TABLE table1_new;
Note: IF you want TO keep your VALUES UNIQUE based ON these FIELDS THEN CREATE UNIQUE INDEX ON your main table.

try this:
Select *, count(month) as cnt from table1 group by Year, Month;
You will get all the months under the different years and either one of the repeating months eliminated.
this

Related

Joining table based on Month in SQL Query

here i have 2 table that i wanted to join.
i have two table. which is table1 and table2. i only able to union between these two tables. Below is my current output table.
However, my expected output is should be like this:
year
month
usage
2022
7
432.738
2022
8
552.306
2022
9
3148.40500
i wanted to join table1 and table2 by sum of usage column based on the month.
Appreciate your help.
You can do SUM/GROUP BY from your query.
select year, month, sum(usage) as usage
from (
YOUR QUERY IN THE PICTURE
) as q
group by year, month
For the future, paste the query as text, not as an image

MS-Access : How to sum multiple values from 2 different tables according to dates with output on 1 date per row

I am still getting started learning Access.
I have 3 tables. Table one has Date as primary key and will have all dates. Tables 2 and 3 (Table 3 is mislabeled in the example image as a second Table 2) will both have 2 columns, Date and Amount. Tables 2 and 3 could have multiple rows with the same date (different amounts) and some may miss dates. I am looking for an output query that would have 1 row for every date in table 2 & 3 that has an amount (some dates may not have an amount in either table) and sums all those amounts for that date in 1 row. Below are example tables and the desired output query. Thanks so much for the newbie help!
I now have this code (Note that I have eliminated Table 1):
SELECT Table2.Dat, Sum(Table2.Amount) AS [Sum Of Amount], Sum(Table2.Tax) AS [Sum Of Tax]
FROM Table2
GROUP BY Table2.Dat;
UNION ALL SELECT Table3.Dat, Sum(Table3.Amount) AS [Sum Of Amount], Sum(Table3.Tax) AS [Sum Of Tax]
FROM Table3
GROUP BY Table3.Dat;
This sums the amounts from same dates for each seperate table, but does not sum the dates for both tables. I imagine it is another GROUP function but I have not been successful in forming it correctly.
Current Results from code above
Try below query.
SELECT tt.mDate AS TransactionDate, Sum(tt.SumOfAmount) AS AmountTotal
FROM (SELECT Table2.tDate as mDate, Sum(Table2.Amount) AS SumOfAmount
FROM Table2
GROUP BY tDate
UNION
SELECT Table3.tDate As mDate, Sum(Table3.Amount) AS SumOfAmount
FROM Table3
GROUP BY tDate) AS tt
GROUP BY tt.mDate;

SQL WHERE IF clause issue

I have a SQL/Java code issue. The basic overlay is as follows: a MySQL database with a table. In this table there are multiple columns. One column consists of names. An associated column is months. In the third column there is counts. So a sample table would be
john - january - 5
john - january - 6
mary - january - 5
Alex - February- 5
John - February - 6
John - February - 4
Mary - February - 3
John - march - 4
The table continues to month May.
So John appears in five months, Mary in 3, and Alex in one. Currently, my SQL query somewhat looks like this.
select name, sum(count)/4
from table where (category ='something'
AND month not like 'May') group by name;
Basically, what this query is supposed to do is just display each name with the average counts per month. Hence, the sum will be divided by four (because I exclude May, so it must divide Jan-April/4). However, the issue is that some names only appear in one month (or two or three).
This means for that name, the sum of the counts would only be divided by that specific number, to get the average counts over the months. How would I go about this? I feel as if this will require some if statement in a where clause. Kind of like where if the count of the distinct (because months may repeat) is a certain number, then divide the sum(count) by that number for each name?
Also, I think it may not be a where if clause issue. I've read some forums where possibly some use of case could be utilized?
If you need average per month, you can GROUP BY name and month and use AVG function:
SELECT `name`, `month`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`, `month`;
If you need average for all period, just GROUP BY name and AVG count:
SELECT `name`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`;
And another option, if you don't like AVG:
SELECT `name`, sum(`count`)/(SELECT count(*) FROM `table` AS `t2` WHERE `category` ='something' AND `month` NOT LIKE 'May' and `t1`.`name` = `t2`.`name`)
FROM `table` AS `t1`
WHERE `category` ='something' AND `month` NOT LIKE 'May')
GROUP BY name;
But I would stay with AVG.
Actually, i prefer to use != instead of NOT LIKE it's improves readability
Just for completness sake here is a WORKING FIDDLE. using the AVG function is the way to go as it will do the average per person per month. look at John in January.. his result is 5.5 when the count (in january) is 5 and 6.. average = 5.5.
SELECT
person,
month,
avg(counter)
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month;
If you want to see the data in one like as it sounds like that from your post then you can do this. ANOTHER FIDDLE
SELECT
person,
group_concat(month),
group_concat(average_count)
FROM(
SELECT
person,
month,
avg(counter) as average_count
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month
) as t
group by person;
Try this :
SELECT name, SUM(count) / COUNT(DISTINCT month)
FROM table
WHERE month != 'May'
AND category = 'something'
GROUP BY name

Count number of bookings between a set of specified dates

I have a table of bookings. I want to count how many bookings occur on each day, starting from specified check in date and check out date. Eg. if check in date was 10-06-2012 and check out date was 14-06-2012 I require a table like this
Date Bookings
10-06-2012 1
11-06-2012 1
12-06-2012 2
13-06-2012 4
14-06-2012 3
I am struggling to get this working. I can count bookings in between the dates but not for each date between check in date and check out date.
I am not sure I understand your question. The query below assumes:
Your bookings table has (at least) columns date, checkin, checkout.
You are looking for bookings where checkin >= 10-06-2012 and checkout <= 14-06-2012.
Here is the query:
SELECT date, COUNT(*)
FROM bookings
WHERE checkin >= '2012-06-10' AND checkout <= '2012-06-14'
GROUP BY date
Use SUM() to find total bookings between a date range.
Try Below :
SELECT Date,SUM(Bookings)
FROM tablename
WHERE Date between 'startdate' AND 'enddate'
GROUP BY Date
First thing you need is a table of dates, day by day. Now mysql is not my thing, so I will try to write down as much info on what I'm doing as I can. Please correct these examples.
Table of dates might be prepared by a job checking for the last booking date and adding missing dates to table of dates. If this is not something you would accept, other solution is to create table dynamically, but there are some perils. To my knowledge there is no way to create such a table, but you can do a practically-working surrogate by selecting distinct dates from your booking table and cross joining this with table of days made in query itself:
((select distinct checkIn from bookings union select distinct checkOut from bookings)
cross join (select 0 union select 1 union select 2 ...))
The list of days should contain as many days as the biggest gap between checkin dates and each checkin and checkout date. This is something you will have to keep an eye on, or simply make the list sufficiently large, for example a hundred days.
Now that you have a table of dates, you need to count bookings matching this date. Complete query would look like this:
select tableOfDates.date, count(bookings.checkIn) bookings
from
(
(
select distinct dates.date + INTERVAL days.day DAY -- OR HOWEVER you add days in mysql
from
(select distinct checkIn date from bookings union select distinct checkOut from bookings) dates
cross join (select 0 day union select 1 union select 2 union 3 union 4 union 5 union 6 union 7) days
)
) tableOfDates
left join bookings
on tableOfDates.date between bookings.checkIn and bookings.checkOut
where tableOfDates.date between [YOUR DATE RANGE]

Help with MYSQL Query Aggregating counts (alternative to three sub-queries)

I am trying to output the total content views from my stats table and group by the year... My stats table is INNODB and has 8M lines and growing...
The table is essentially ID, DATE, MAKE, IP, REFERRER (indexes on id,date,make)
Each entry has an auto-incremented ID, the entry date YYYY-MM-DD HH:MM:SS, and a product make like 'sony', 'panasonic' etc...
I am trying to make a query that does not kill my server that sums up the total content views per year and shows them in order from most viewed to least viewed...(for this year 2011) so that I can use that data to populate a JS chart comparing this year with the past years. I can do this with multiple queries and walking through arrays in PHP but I think there should be a way to get this in one query, but hell if I can figure it out.
Any ideas? Also, am I better to make three independent queries and deal with the results in PHP or can I get this into one query that is more MYSQL efficient.
The output I would like to see (although I cannot seem to make it do this), is simply
MAKE 2009Total 2010Total 2011Total
---- --------- --------- ---------
Panasonic 800 2345 3456
Sony 998 5346 2956
JVC 1300 1234 1944
Assume my table has data in it from 2009 to now, I need my array to contain one line per make...
Any help would be appreciated... I am amazed at how fast results like this come back from analytics tools and mine take about 75seconds on 4x Quad-core XEON RAID mysql server... this stats table is not being written to but once a day to dump in the previous day's stats so I am not sure why my 3 sep queries are so slow... hence my question... maybe a single query won't be any faster?
Anyway, any help would be appreciated and opinions about speeding up stats queries from a generic view stats table would be welcomed!
I have made an observation. Your query is requesting by year. You should do two things:
store the year
create a better index (product,year)
Here is how yuou can do so:
CREATE TABLE stats_entry_new LIKE stats_entry;
ALTER TABLE stats_entry_new ADD COLUMN entryyear SMALLINT NOT NULL AFTER date;
ALTER TABLE stats_entry_new ADD INDEX product_year_ndx (product,year);
ALTER TABLE stats_entry_new DISABLE KEYS;
INSERT INTO stats_entry_new
SELECT ID, DATE,YEAR(date),product,IP,REFERRER FROM state_entry;
ALTER TABLE stats_entry_new ENABLE KEYS;
ALTER TABLE stats_entry RENAME stats_entry_old;
ALTER TABLE stats_entry_new RENAME stats_entry;
Now the query looks like this:
SELECT A.product,B.cnt "2009Total",C.cnt "2010Total",D.cnt "2011Total"
FROM
(SELECT DISTINCT product FROM stats_entry) A
INNER JOIN
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2009 GROUP BY product) B
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2010 GROUP BY product) C
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry WHERE entryyear=2011 GROUP BY product) D
USING (product);
Now to be fair, if you do not want to add a year to the table then you still have to make an index
ALTER TABLE stats_entry ADD INDEX product_date_ndx (product,date);
Your query looks like this now
SELECT A.product,B.cnt "2009Total",C.cnt "2010Total",D.cnt "2011Total"
FROM
(SELECT DISTINCT product FROM stats_entry) A
INNER JOIN
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2009-01-01 00:00:00'
AND date <= '2009-12-31 23:59:59'
GROUP BY product) B
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2010-01-01 00:00:00'
AND date <= '2010-12-31 23:59:59'
GROUP BY product) C
USING (product)
(SELECT product,COUNT(1) cnt FROM stats_entry
WHERE date >= '2011-01-01 00:00:00'
AND date <= '2011-12-31 23:59:59'
GROUP BY product) D
USING (product);
Give it a Try !!!
SELECT make,year(date) as year,sum(views)
FROM `stats `
group by make,year
o/p :
MAKE year sum
------- ------- ---------
Panasonic 2009 800
Panasonic 2010 2345
Panasonic 2011 3456
....
you can later seggregate on the php side.
or:
select make ,group_concat(cast(yr_views as char)) as year_views
from (SELECT make,concat(year(date),':',sum(views)) as yr_views
FROM `stats`
group by make,year(date))as make_views
group by make
o/p:
make year_views
------ ---------------
panasonic 2009:800,2010:2345,2011:3456
...
Later, explode at the PHP level & have the result.