GROUP BY a certain value on rows used as columns - php

I have a table of survey data where lines of results are separated into many rows by, each having their own variable name.
My table looks like this:
data_id data_content var_name var_line
1 1 SERIAL 1
2 2 GND.AGE 1
3 3 GND.NEWS.FREQ 1
4 2 SERIAL 2
5 3 GND.AGE 2
6 3 GND.NEWS.FREQ 2
7 3 SERIAL 3
8 3 GND.AGE 3
9 4 GND.NEWS.FREQ 3
Here is my current query to retrieve the total number of answers for every possible answer of GND.NEWS.FREQ. As in the total number:
SELECT *, COUNT(*) as total
FROM `data`
WHERE `var_name` = 'GND.NEWS.FREQ'
GROUP BY `data_content`
Now I need to add the functionality to only return answers where GND.AGE for example is 3. So basically treat all rows where var_line = 1 as a single row.
I have looked up pivot tables but I'm not sure how to add that into my current query.
I would like to do this in one query if possible but I wouldn't mind doing something like getting var_line IDs in a separate query.

Unfortunately MySQL does not have a PIVOT function which is basically what you are trying to do. So you will need to use an aggregate function with a CASE statement. If you have a unknown number of var_name values that you want to turn into columns, then you can use prepared statements:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when var_name = ''',
var_name,
''' then var_line end) AS ',
replace(var_name, '.', '_')
)
) INTO #sql
FROM data;
SET #sql = CONCAT('SELECT data_content,', #sql, '
from data
group by data_content
');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo

Related

MYSQL Ordering Substring Count

i want to order my query by counts of the substring.
Table :
id shop_update
1 a,b,c
2 a,b
3 c
4 a,'',c
I just to order this by count
id shop_update count
1 a,b,c 3
2 a,b 2
3 c 1
4 a,'',c 2
My query is
$this->db->select("*,LENGTH(shop_update) - LENGTH(REPLACE(shop_update,',','')) AS counts");
$this->db->order_by("counts","DESC");
$this->db->from('at_shop');
but it returns 0 only in the count
id shop_update count
1 a,b,c 0
2 a,b 0
3 c 0
4 a,'',c 0
my issue is LENGTH(REPLACE(REPLACE(shop_update,',',''),'''','')) it was running with space like LENGTH(REPLACE(REPLACE(shop_update,', ',''),'''',''))
(spaces are added between (', ')in the query but actual code the spaces are not there)
Please see the difference
Any help?
Just by using this function in the query will give you the correct count:
LENGTH(REPLACE(REPLACE(shop_update,',',''),"' '",''))
See a working example of the same here: http://www.sqlfiddle.com/#!2/fa7a5/7
SELECT *
FROM tablename
ORDER BY LENGTH( REPLACE( shop_update, ',', '' ) ) DESC
You may use this command
SELECT id,shop_update,LENGTH(replace(shop_update,"''","")) as count FROM table_name ORDER BY count desc

PHP function to find the median of a column in MySQL

I have a database, db and in it a table, Table.
It looks somewhat like:
id | val
--------
1 | 45
2 | 35
3 | 23
4 | 49
5 | 67
6 | 12
7 | 0
8 | 87
9 | 46
(This is just an example data set. Actual data set is huge. And I need to work in least time possible.)
I need to find the median of the column val. Actually I need a php function to be used multiple times.
A similar question does exist: Simple way to calculate median with MySQL
I tried a few answers in this question, none of them worked for me. The accepted answer doesn't work since it used to work with an older version of SQL only.
PS: It should also work in the case of many duplicates.
just for fun i thought i try and do it all in MySQL, here's the sqlFiddle
SELECT
CASE
WHEN MOD((select count(*) as count from t),2)=1 THEN
(select val from
(select #row:=#row+1 as row,val
from t,(select #row:=0)r
order by val)t1
where t1.row = CEIL((select count(*) as count from t)/2)
)
ELSE
((select val from
(select #row:=#row+1 as row,val
from t,(select #row:=0)r
order by val)t1
where t1.row = (select count(*) as count from t)/2)+
(select val from
(select #row:=#row+1 as row,val
from t,(select #row:=0)r
order by val)t1
where t1.row = ((select count(*) as count from t)/2)+1))/2
END AS median
Just replace occurences of t with your table name, don't change t1.
Also if the table has no rows, it'll return NULL as median.
This query can be further reduced to the below (sqlFiddle)
SELECT #rowCount:=(select count(*) as count from t) AS rowcount,
(select AVG(val) from
(select #row:=#row+1 as row,val
from t,(select #row:=0)r
order by val)t1
where t1.row IN (FLOOR((#rowCount+1)/2),
CEIL((#rowCount+1)/2)
)
) as Median
It'll return 2 columns, a rowcount column and a median column. I put the rowcount column there because i didn't want to count from t multiple times like previous query.

PHP mySQL query to return a reordered list and count occurences of field value even if absent

Basically, I have a mysql db table which contains a datetime column and a category column. I want to create a SQL query to retrieve all the values present in the category column and count how many occurences of each category values grouped by month/year of the datetime column. If it is possible, I'd also like totals to be returned. A total for the number of all occurences in a month and a total of category counted.
Note: the category values cannot be hardcoded because they are set by the user and stored in another table.
DB table has following structure:
datetime | category
2009-01-05 | fish
2009-01-06 | fish
2009-01-06 | potato
2009-01-16 | fish
2009-02-08 | pineapple
2009-02-15 | potato
I wish returned result from query would be:
Month | fish | potato | pineapple | total
2009-01 | 3 | 1 | 0 | 4
2009-02 | 0 | 1 | 1 | 2
Total | 3 | 2 | 1 | 6
I think (hope) it can be done in a single SQL query but I can't figure out how.
Can anyone help me?
Thanks!
Let me first say that I think this feels more like an issue to handle in your presentation logic (php code). However, SQL can produce such a result. You are trying to accomplish two different things.
First, you're looking for a PIVOT table. MySQL does not support the PIVOT command, but you can simulate it with MAX and CASE. This works well when you know the number of potential categories, but won't work in your case.
Next, you want to have row totals and then a final total row. Again, this is more appropriate to handle in the presentation layer.
However, using Dynamic SQL, you can achieve both a PIVOT table and row totals. Here is some sample code:
First build your PIVOT variable #sql:
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'COUNT(IF(category = ''', category, ''',1,NULL)) AS ', category)
) INTO #sql
FROM (
SELECT *,
#rn:=IF(#prevMonthYear=CONCAT(YEAR(datetime),'-',MONTH(datetime)),#rn+1,1) rn,
#prevMonthYear:=CONCAT(YEAR(datetime),'-',MONTH(datetime)) dt
FROM yourtable JOIN (SELECT #rn:=0,#prevParent:=0) t
) t
;
Now build your Row Summary variable #totsql:
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(', category, ') AS sum_', category)
) INTO #totsql
FROM (
SELECT *,
#rn:=IF(#prevMonthYear=CONCAT(YEAR(datetime),'-',MONTH(datetime)),#rn+1,1) rn,
#prevMonthYear:=CONCAT(YEAR(datetime),'-',MONTH(datetime)) dt
FROM yourtable JOIN (SELECT #rn:=0,#prevParent:=0) t
) t
;
Put it all together:
SET #sql = CONCAT('SELECT dt,
', #sql, ', COUNT(1) total
FROM (
SELECT *,
#rn:=IF(#prevMonthYear=CONCAT(YEAR(datetime),''-'',MONTH(datetime)),#rn+1,1) rn,
#prevMonthYear:=CONCAT(YEAR(datetime),''-'',MONTH(datetime)) dt
FROM yourtable JOIN (SELECT #rn:=0,#prevParent:=0) t
) t
GROUP BY dt
UNION
SELECT ''Totals'',', #totsql, ', SUM(total)
FROM (
SELECT dt,
', #sql, ', COUNT(1) total
FROM (
SELECT *,
#rn:=IF(#prevMonthYear=CONCAT(YEAR(datetime),''-'',MONTH(datetime)),#rn+1,1) rn,
#prevMonthYear:=CONCAT(YEAR(datetime),''-'',MONTH(datetime)) dt
FROM yourtable JOIN (SELECT #rn:=0,#prevParent:=0) t
) t
GROUP BY dt
) t2
;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SQL Fiddle Demo
Results:
MONTH FISH POTATO PINEAPPLE TOTAL
2009-1 3 1 0 4
2009-2 0 1 1 2
Totals 3 2 1 6
You can have multiple nested queries or you can use mysql loops in this case. Easiest thing would be to get all the data you need and process it using php.

get SUM of another row of GROUP BY'd rows

I have this table:
This selection is is duplicated many times for different var_lines (which pretty much work as one row of data, or respondent for a survey) and set_codes (different survey codes).
With this query:
SELECT
*, COUNT(*) AS total
FROM
`data`
WHERE
`var_name` = 'GND.NEWS.INT'
AND(
`set_code` = 'BAN11A-GND'
OR `set_code` = 'BAN09A-GND'
OR `set_code` = 'ALG11A-GND'
)
AND `country_id` = '5'
GROUP BY
`data_content`,
`set_code`
ORDER BY
`set_code`,
`data_content`
The query basically counts the number of answers for a specific question. Then groups them survey (set_code).
What I need is for each of the grouped data_content answers for GND.NEWS.INT to also show the SUM of all the corresponding GND_WT with the same var_line.
For example if I had this:
data_id data_content var_name var_line
1 2 GND.NEW.INT 1
2 1.4 GND_WT 1
3 2 GND.NEW.INT 2
4 1.6 GND_WT 2
5 3 GND.NEW.INT 3
6 0.6 GND_WT 3
I would get something like this:
data_id data_content var_name var_line total weight
1 2 GND.NEW.INT 1 2 3
5 3 GND.NEW.INT 3 1 0.6
Thanks for any help.
Your requirements are not exactly clear, but I think the following gives you what you want:
select d1.data_id,
d1.data_content,
d1.var_name,
d1.var_line,
t.total,
w.weight
from data d1
inner join
(
select data_content,
count(data_content) Total
from data
group by data_content
) t
on d1.data_content = t.data_content
inner join
(
select var_line,
sum(case when var_name = 'GND_WT' then data_content end) weight
from data
group by var_line
) w
on d1.var_line = w.var_line
where d1.var_name = 'GND.NEW.INT'
See SQL Fiddle with Demo
This Query can be suitable for your specific example:
select st.data_id,
st.data_content,
st.var_name,
st.var_line,
count(st.data_id) as total,
sum(st1.data_content) as weight
from data st
left join data st1 on st1.var_name = 'GND_WT' AND st1.var_line=st.var_line
where st.var_name='GND.NEW.INT'
group by st.data_content
Regards,
Luis.

How to write this kind of a query in mysql?

I have a table like this
a_count b_count total_count(a_count+b_count)
2 3
5 1
4 7
5 0
This is my table I need to update total count field using a single query. How can I write that kind of a query?
I need output like this
a_count b_count total_count(a_count+b_count)
2 3 5
5 1 6
4 7 11
5 0 5
To update the values of those fields in the table:
UPDATE mytable SET total_count = a_count + b_count
To get those fields from the table:
SELECT a_count, b_count, total_count FROM mytable
To get those fields without that total_count column:
SELECT a_count, b_count, (a_count+b_count) AS total_count FROM mytable
You can also write a trigger for that
DELIMITER //
CREATE TRIGGER `total_count` BEFORE INSERT OR UPDATE on `table`
FOR EACH ROW BEGIN
SET NEW.total = NEW.a+NEW.b;
END;
//
DELIMITER ;

Categories