mysql count unique cell combinations, with null - php

I'm trying to use either a PHP file or SQL that will go through a large data table to count the amount of combinations of cells and count them in a new data_sum table.
I have an idea for a PHP file in the works:
$popdata = mysql_query("SELECT * FROM data");
while($add = #mysql_fetch_array($popdata)){
$qitem1 = "SELECT * FROM data_sum WHERE item1='".$add['item1']."'";
$ritem1 = mysql_query($qitem1);
if(mysql_num_rows($ritem1) > 0){
while($add2 = #mysql_fetch_array($ritem1)){
$qitem2 = "SELECT * FROM data_sum WHERE item2='".$add['item2']."'";
$ritem2 = mysql_query($qitem2);
if (mysql_num_rows($ritem2) > 0){
$sql = "UPDATE Count=Count + 1 WHERE item1='".$add['item1']."' AND item2='".$add['item2']."'";
$update = mysql_query($sql);
} else{
$sql = "INSERT INTO data_sum (item1, item2) VALUES('$item1', '$item2')";
$insert = mysql_query($sql);
}
} else{
$sql = "INSERT INTO data_sum (item1, item2) VALUES('$item1', '$item2')";
$insert = mysql_query($sql);
}
If I have a table :
`data`
item1 item2
1 (this row counts to both the '1,2' duo as well as the '1,3')
1 2
1 3
1 3
2 3
And I want to condense it to something like:
`data_sum`
item1 item2 Count
1 2 2
1 3 3
2 3 1
Yes, I know there are only 5 rows in data and the count is a total of 6. I want the cells with nothing in them to count towards each possible branch. Is there a way to do this in SQL with COUNT or UNIQUE or DISTINCT? Thanks!

,
The following query does what you want, by doing the calculation for the two groups separately:
select base.item1, base.item2, base.cnt + coalesce(sum(extra.cnt), 0)
from (select item1, item2, count(*) as cnt
from data
where item1 is not null and item2 is not null
group by item1, item2
) base join
(select item1, item2, count(*) as cnt
from data
where item1 is null or item2 is null
group by item1, item2
) extra
on base.item1 = extra.item1 or
base.item2 = extra.item2 or
(extra.item1 is null and extra.item2 is null)
group by base.item1, base.item2, base.cnt;
Here is a SQL Fiddle.

Related

Fetch row with different data on same column

We have the table structure like
Fieldid userid data
41 2 1
12 2 0
41 3 1
12 3 1
We want the user which have (data=1 and filedid = 41) and (data = 0 and filedid=12)
We tried the query
select userid from table
where (data=1 and filedid = 41)
AND (data = 0 and filedid=12)
but it returns empty results.
Can anyone help how we will get the record using MySQL?
You can use grouping with a conditional aggregate in the HAVING clause:
SELECT userid
FROM mytable
GROUP BY userid
HAVING COUNT(CASE WHEN data = 1 AND FieldId = 1 THEN 1 END) >= 1 AND
COUNT(CASE WHEN data = 0 AND FieldId = 12 THEN 1 END) >= 1
you need to use union all like:
select * from table1 where Fieldid = 41 and data = 1 union all
select * from table1 where Fieldid = 12 and data = 0
attached image shows the output
Similar to #Giorgos, with multicolumn compare for conciseness:
select userid
from t
group by userid
having sum((data,fieldId) = (1, 41)) > 0
and sum((data,fieldId) = (0, 12)) > 0
When searching for results with one or another set of data you have to use OR keyword, not AND.
SELECT userid FROM table
WHERE (data = 1 AND filedid = 41)
OR (data = 0 AND filedid = 12)

MySql Tally system with php

I'm trying to condense data that I have in my database into rows with their points tallied to see the most popular.
If I had a data table like:
`data`
item1 item2
1
1 2
1 3
1 3
2 3
And wanted the condensed version to be:
`data_sum`
item1 item2 Tally
1 2 2
1 3 3
2 3 1
How would I achieve this? I have somewhat of an idea here:
$popdata = mysql_query("SELECT * FROM data");
while($add = #mysql_fetch_array($popdata)){
$qitem1 = "SELECT * FROM data_sum WHERE item1='".$add['item1']."'";
$ritem1 = mysql_query($qitem1);
if(mysql_num_rows($ritem1) > 0){
$qitem2 = "SELECT * FROM data_sum WHERE item2='".$add['item2']."'";
$ritem2 = mysql_query($qitem2);
if (mysql_num_rows($ritem2) > 0){
$sql = "UPDATE Tally=Tally + 1 WHERE item1='".$add['item1']."' AND item2='".$add['item2']."'";
$update = mysql_query($sql);
}
else{
$sql = "INSERT INTO data_sum (item1, item2) VALUES('$item1', '$item2')";
$insert = mysql_query($sql);
}
else{
$sql = "INSERT INTO data_sum (item1, item2) VALUES('$item1', '$item2')";
$insert = mysql_query($sql);
}
Yes, I know the total tallies are one more than the rows in the first table. I want the rows with a null column to count towards both tallies with a common factor. This file is going to go through thousands of rows so I want utmost efficiency! Thanks!
All you would need to do is create a new table and then combine an INSERT statement with a GROUP BY'd SELECT statement. This would COUNT() the number of times item1 and item2 were the same and store them in the new tally'd table.
Something along the lines of:
INSERT INTO new_tally_table (item1, item2, Tally)
SELECT item1, item2, COUNT(*)
FROM table
GROUP BY item1, item2
Edit:
Actually re-read the last bit of your question. Think what you want is something like this:
SELECT item1, item2, COUNT(*)
FROM (
SELECT i1.item1, i2.item2
FROM table1 as i1
INNER JOIN (
SELECT DISTINCT item1, item2
FROM table1 WHERE item2 IS NOT NULL
) as i2 ON (i1.item1 = i2.item1)
WHERE i1.item2 IS NULL
UNION ALL
SELECT item1, item2
FROM table1
WHERE item2 IS NOT NULL
) as t
GROUP BY item1, item2
There's probably a better way of writing that though.
There may be a simpler solution, but I can't think of it...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,item1 INT NULL
,item2 INT NULL
);
INSERT INTO my_table (item1,item2) VALUES
(1 ,NULL),
(1 ,2),
(1 ,3),
(1 ,3),
(2 ,3);
SELECT x.item1
, x.item2
, COUNT(DISTINCT y.id)
FROM my_table x
JOIN my_table y
ON y.item1 = x.item1
AND (y.item2 = x.item2 OR y.item2 IS NULL)
AND y.id <= x.id
JOIN
( SELECT item1
, item2
, MAX(id) max_id
FROM my_table
GROUP
BY item1
, item2
) z
ON z.item1 = x.item1
AND z.item2 = x.item2
AND z.max_id = x.id
WHERE x.item2 <> 0
GROUP
BY x.id;
+-------+-------+----------------------+
| item1 | item2 | COUNT(DISTINCT y.id) |
+-------+-------+----------------------+
| 1 | 2 | 2 |
| 1 | 3 | 3 |
| 2 | 3 | 1 |
+-------+-------+----------------------+

mysqli querying 2 tables, but retrieve only results not in the other table

Is there any way to make a single query statement?
left_table
id|group_id|member_id
---------------------------------
1|10|100
2|13|100
3|14|100
4|13|103
5|14|102
right_table
id|user_id|group_name
-----------------------------------------
10|100|hundred
11|101|hundredone
12|102|hundredtwo
13|103|hundredthree
14|104|hundredfour
$query_id = 100
$results = mysqli_query($link, "SELECT * FROM right_table rt, left_table lt WHERE rt.user_id != '$query_id' and rt.id = lt.group_id and
lt.member_id != '$query_id'");
while ($r = mysqli_fetch_array($results)){
echo $r['group_name'].'<br>';
}
When i query both the table, i only want to retrieve the group name from right table
where my $query_id is not in the left_table(member_id)
desire output for user_id 100 would be hundredone and hundredtwo because the member_id 100 is not part of
any 11 and 12 group from the right_table
SELECT group_name
FROM right_table rt
WHERE NOT EXISTS (
SELECT 1
FROM left_table lt
WHERE lt.member_id = 100
AND lt.group_id = rt.id
)

PHP/Mysql: 2 selects from same table in one query

This is how my table looks like:
id | name | value
-----------------
1 | user1| 1
2 | user2| 1
3 | user3| 3
4 | user4| 8
5 | user5| 6
6 | user7| 4
7 | user8| 9
8 | user9| 2
What I want to do is to select all the other users, in one query, who's value is user1's value lower than it's value plus 3, higher than it's value minus 3 or equal to it's value.
Something like this:
$result = mysqli_query($con,"SELECT * FROM users WHERE value<'4' OR value>'-2'") or die("Error: ".mysqli_error($con));
while($row = mysqli_fetch_array($result))
{
echo $row['name'].'<br/>';
}
The problem is that users1's value can vary every time the query is run.
Sorry for lame names, but this should work:
NOTE: I named table with your data as "st".
SELECT b.user, a.value as "user1val", b.value as "otheruservalue" FROM st as a
join st as b
on a.user = "user1" and a.user != b.user
where
(b.value > (a.value - 3)) and (b.value < (a.value + 3))
We get unique pairs of user1's value and other user's value by joining same table. After that we just do some simple comparison to filter rows with suitable values.
$user1 = mysql_fetch_assoc(mysql_query("SELECT `value` FROM `users` WHERE id='1'"));
$result = mysql_query("SELECT * FROM `users` WHERE value<'".$user1['value']."+3' OR value>'".$user1['value']."-3'");
Or nested queries :
$result = mysqli_query($con, "select * from `users` where `value` < (select `value` from `users` where `name`='user1')+3 OR `value` > (select `value` from `users` where `name`='user1')-3");

Checking users options from default

I have table:
user_id | song_id| points
--------|----------------
2 | 1 | 0
2 | 2 | 1
2 | 3 | 2
2 | 4 | 3
2 | 5 | 4
And I need to check if the user have changed the points value.
Therefore it should be something like:
while ($row = mysql_fetch_array($query)) {
$userID = $row['user_id'];
$songID = $row['song_id'];
$points = $row['points'];
if($songID-$points==1){
echo $userID."<br>";
}
But this will print out every occasion of userID where the song-id - points=1.
I need to print out only these user_id's that have all the values =1 and the username must echo'd only once.
EDIT:
SELECT DISTINCT user_id WHERE (song_id - points) = 1
This is half way there. This echo's user_ids' where the song_id - points = 1, but if the user is reordered (i use jQuery sortable) the list, then there can be some rows that is "song_id - points = 1".
My script must echo only these user_id-s, where users every song_id - points = 1, not only one
SELECT DISTINCT user_id FROM table WHERE (song_id - points) = 1
After edit:
SELECT table.user_id
FROM table
LEFT JOIN (
SELECT user_id, COUNT(*) AS C FROM table) AS T2
ON table.user_id = T2.user_id
WHERE (table.song_id - table.points) = 1
GROUP BY table.user_id
HAVING COUNT(*) = T2.C
You can first filter the users which has modified point values:
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
Then you can use fetch the users which doesn't fit the above condition:
SELECT DISTINCT user_id FROM table
WHERE user_id NOT IN (
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
)
According to your last edit this last SQL statement might work.
You can check a working example.
Here is what you're looking for:
select user_id from (
select user_id, if(song_id - points = 1, 0, 1) flag from t
) as S
group by user_id
having sum(flag) = 0
And here is a working example.
In case I didn't understand the requirements this shows all users who don't even have one row in which song_id - points != 1, i.e, all users who have all rows that match song_id - points = 1
Or maybe, if you prefer a different approach that might be more efficient:
select distinct t1.user_id from t t1
where not exists (
select * from t t2
where t2.song_id - t2.points != 1 and t1.user_id = t2.user_id
)
Here is the working example.
Not sure I understand the why of the situation, but a simple control-break structure will achieve the desired result ...
$old_id = '';
$good = false;
while($row = mysql_fetch_array($query)){
//check to see if we have a new user ...
if($row['user_id'] != $old_id){
//check to see if all values were == 1
if($good){
echo $old_id . '<br />';
}
//re-initialize variables
$good = true;
$old_id = $row['user_id'];
}
//if value != 1, we won't print the user ...
if($row['song_id'] - $row['points'] != 1){
$good = false;
}
}
//final end-of-loop condition ...
if($good){
echo $old_id . '<br />';
}
OK, here's a query that's a lot more simple than the join above:
SELECT user_id, sum(song_id) as song_total, sum(points) as point_total, count(*) AS cnt FROM table GROUP BY user_id
If the difference between song_id and points is 1 for every song, then the difference between the totals will equal the number of rows for that user ... so using this query:
while($row = mysql_fetch_array($query)){
if($row['cnt'] == ($row['song_total'] - $row['point_total'])){
echo $row['user_id'] . '<br />';
}
}

Categories