I have a mysql table where I like to perform a query on. My table looks as following:
date activity amount
-------- ------ --------
day 1 drink 0
day 1 eat 1
day 1 breath 1
day 2 drink 0
day 2 eat 0
day 2 breath 0
day 3 drink 1
day 3 breath 0
day 4 eat 1
etc
etc
etc
What i'd like to do is to see when eat is 1, and for the days that is the fact, i'd like to display all activities for those days
//What I was doing right now is:
$activityarray = array();
$result = mysql_query("SELECT * FROM table WHERE activity='eat' AND amount='1'");
$row = mysql_fetch_assoc($result);
//this returns all rows where activity=eat and amount=1
do{
//perform for each result row a new query; look for the 'date'=$row[date] from the first query and show all activities that have been done that day (activity=1)
$result2 = mysql_query("SELECT * FROM table WHERE date='".$row[date]."'");
$row2 = mysql_fetch_assoc($result2);
do{
array_push($activityarray,$row2['activity']);
}while($row2 = mysql_fetch_assoc($result2));
}while($row = mysql_fetch_assoc($result));
print_r($activityarray);
Since there are thousands of days and dozens of activities per day, this seems not to be the most efficient method to me. Is there a way I can do this more efficient with one query? (So: check all activities for the days that eat=1).
Hope anyone could me me out!
Use a self-join:
SELECT t1.*
FROM table AS t1
JOIN table AS t2 ON t1.date = t2.date
WHERE t2.activity = 'eat' AND t2.amount = 1
My suggestion, especially if you have join size restrictions:
select *
from table as t1
where exists (
select 1
from table as t2
where t2.date = t1.date
and t2.activity = 'eat'
and t2.amount = 1
)
Related
How can I count users with two consecutive absences only? I have to create a chart to show frequency absences by employee.
My table name = incidencias
id | name | dateA | description
1 | al |2017-08-01| absence
2 | al |2017-08-02| absence
3 | alex |2017-08-01| absence
4 | alex |2017-08-02| absence
5 | alex |2017-08-03| absence
6 | al2 |2017-08-01| absence
7 | al2 |2017-08-02| absence
I want the result to be 2, only al and al2 have two consecutive dates where description = absence.
I´m using php to run the query, i did try this code i found but and I tested it in sqlfiddle and works great,. but not in my host.I think this is for PostgreSQL.
$query2 = mysqli_query($conn, "SELECT name,
sum(diff) as days,
(dateA) as work_start,
(dateA) as work_end
FROM (SELECT name,
dateA,
diff
FROM (select name,
dateA,
nvl(dateA- lag(dateA) over (partition by name order by dateA),1) as diff
from incidencias
where description = 'absence'
) t1
where diff = 1
) t2
group by name
having sum(diff) = 2");
$row_cnt = mysqli_num_rows($query2);
printf("Result set has %d rows.\n", $row_cnt);
I would really appreciate it.
So, this is normally done through JOINing on to the same table.
SELECT oinc.*
FROM incidencias oinc
LEFT JOIN
incidencias iinc
ON (oinc.name = iinc.name AND oinc.description = iinc.description)
WHERE description = 'absence'
AND oinc.dateA = DATE_ADD( iinc.dateA, 'INTERVAL 1 DAY');
So, line by line:
SELECT oinc.* -- grab me everything from the oinc table
FROM incidencias oinc -- We're going to call incidencias "oinc" in this query
-- "oinc" is now an alias for "incidencias"
LEFT JOIN -- I want a result whether or not the result is duplicated.
-- (Technically, by including the condition that it not be duplicated
-- this is the same thing as an "INNER JOIN".)
incidencias iinc -- We're looking at the same table, better call it something else
ON (oinc.name = iinc.name AND oinc.description = iinc.description)
-- We're matching the name and the description between the two
-- aliases of the table (oinc, iicn)
WHERE description = 'absence' -- Should be obvious
AND oinc.dateA = DATE_ADD( iinc.dateA, 'INTERVAL 1 DAY'); -- the iinc alias
-- has a date which is one day less than the oinc alias
Some side notes:
I used left join so that you can omit the AND ... later.
You should experiment with moving that AND query from the WHERE into the ON clause. Then you can use an INNER join. You'll get the same results, but knowing both will help you more later.
Here's one way (there may be a simpler solution, but this should be fast anyway)...
SELECT COUNT(*)
FROM
( SELECT name
, MAX(i) i
FROM
( SELECT x.*
, CASE WHEN #prev_name = name THEN
CASE WHEN #prev_date = datea - INTERVAL 1 DAY THEN #i:=#i+1 ELSE #i:=1 END
ELSE #i:=1 END i
, #prev_name := name
, #prev_date := datea
FROM my_table x
, ( SELECT #prev_name:=null,#prev_date:=null, #i:=1) vars
WHERE x.description = 'absence'
ORDER
BY name
, datea
) b
GROUP
BY name
HAVING i = 2
) p;
I am tring to get difference between frequency, so first row minus next rows,second row minus third row,etc. However, my id in the table like below. So I cannot use minus 1 to get the previous row, and I trying to use <, but not working,help, appreciate.
id game number frequency
1 a 3 4
5 c 3 5
6 a 3 7
9 a 2 9
13 a 2 19
My query is:
SELECT t1.frequency-t2.frequency as diff
FROM $table as t1
JOIN $table as t2 ON t2.id < t1.id
WHERE t1.game=a AND t1.num=2
A php solution for your requirement could be this:
$result = mysqli_query($connection, "SELECT * FROM $tableName");
$rows = mysqli_fetch_all ($result, MYSQLI_ASSOC);
for($i=0; i<count($rows)-1; i++){
echo ( abs($rows[$i]-$rows[$i+1) );
}
I have an existing table with millions of entries (growing) that consists of:
userid|name|etc...
1 frank ...
1 frank ...
2 joe ...
5 sam ...
1 franky ...
What I need to do is return a table of:
place|name|total
1 franky 3
2 sam 1
3 joe 1
Where total is the SUM(userid = the distinct userid).
Currently I'm doing a query to SELECT DISTINCT userid from table and then foreach returned value in php, I'm doing another query to return the name and sum(userid = userid).
As you can assume, this is very taxing and takes a long time now with all of the values. Is there any way to speed this up by doing 1 query?
i think you need
SELECT #a:=#a+1 AS `place`, name, COUNT(userid) AS `total`
FROM `your_table`, (SELECT #a:= 0) AS a
GROUP BY userid
SELECT userid, COUNT(*)
FROM some_table
GROUP BY userid
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.
I’ve two tables (MySQL): player and scores. In scores table are stored annual scores in this way:
player_id | 2002 | 2003 | 2004
1 | 5 | 6 | 4
2 | 3 | 2 | 5
Etc.
I write the follow code to make a ranking based on last year scores.
$extract = mysql_query("SELECT * FROM players AS p, scores AS s WHERE p.player_id =s.player_id ORDER BY s.2004 desc");
while ($row = mysql_fetch_assoc($extract)) {
$name = $row['name'];
$score = $row['2004'];
if ($row['2004'] < $row['2003']) {
$value = "-";
}
else if ($row['2004'] > $row['2003']) {
$value = "+";
}
else if ($row['2004'] == $row['2003']) {
$value = "=";
}
echo "<b>".$name."</b> | ".$score." ".$value."<br>\n";
}
But this code has two big problems:
1) In the query I have to specify the last year (ORDER BY s.2004), so if I add another column (eg. 2005) into scores table, I have to manually change the code.
2) Same thing for the “$value” var. If I add 2005, the comparison between 2004 and 2003 becomes wrong (it should be between 2005 and 2004).
I know I have to use loops and array but... how?
You should redesign your scores table to store player_id, score and year in one row. So, each score gets its own row. When you find yourself duplicating columns, you are usually heading in the wrong direction.
Then, your query would look like:
Select Year(CURDATE());
select *
from players p
inner join scores s on p.player_id = s.player_id
where s.`Year` = Year(CURDATE()) --or (select max(Year) from Score)