AND operation within mysql records - mysql

I have a set of records which return flags in individual records. Based on that flags I want to perform and operation within those flags (e.g.if any single flag is "true" final result should return me "true")
Following are the set of records which is returned by normal SQL query ;
select ID,flag from tablename;
--------------------------
ID(int) | flag (varchar(5))
--------------------------
1 | true
2 | false
3 | true
4 | false
5 | false
I would like to know the SQL query which returns result as shown below (such a way that final result should be and operation within each of those 5 records)
-------
flag
-------
true

I'm not sure I completely understand what you want to do, but if you want to define your AND operation as "at least one of the records must have as its flag value 'true'", you can use the following SQL statement which will return 1 if there is at least one 'true' value and otherwise will return 0:
SELECT IF(COUNT(*) > 0, 'true', 'false')
FROM Table1
WHERE flag = 'true';
See the SQL Fiddle: http://sqlfiddle.com/#!2/1e6cd7/11

i came up with this solution but maybe you will get a short and better one :) .
select if(count(*) = 1 , 'mixed' , flag) flag from(
select flag from table1
where flag = 'true'
having count(*) = 5
union
select flag from table1
where flag = 'false'
having count(*) = 5
union
select 'mixed' from table1
)t
DEMO TO PLAY WITH

Related

query using SOME in mysql not giving expected results.?

Suppose I have a table :
start_range end_range
1 4
4 8
I want the result to be true if it is greater than any of the value of start_range and less than any of the corresponding end_range.
Eg.
value 2 should return true , as 2>1 and 2<4
but value 4 should return false in this case as 4>1 but 4<4 becomes false, as well as 4>4 becomes false for the second case.
I cannot use the query
SELECT Sumthing
FROM XYZ
WHERE value> SOME(start_range) AND value < SOME(end_range)
The problem with the above query is let say value = 4.
Now 4> SOME(start_range) will become true as 4>1. AND
4< SOME(end_range) will also become true as 4<8.
But in actual the comparison should be like (((4>1)AND(4<4)) OR ((4>4)AND(4<8))) . It should return false.
One more thing , the above table is not persistent , I have been creating it in a subquery.Thats why i have been using SOME.
if still my question isn't clear, mention in comments.
Assuming that xyz is your table:
select (count(*) > 0) as HasMatch
from xyz
where value > start_range and value < end_range;
I'm not sure why you are using some.
EDIT:
It occurs to me that you want to use subqueries, and xyz is not the table in question. Perhaps this is what you want:
select xyz.*
from xyz
where exists (select 1
from (<your query here>) t
where xyz.value > t.start_range and xyz.value < t.end_range
);
you can do something like this
SELECT CASE WHEN start_range<value and end_range>value
THEN 'true'
ELSE 'false'
END here_name_to_this_column(optional)
FROM table_name
tutorial link
select (count(*) > 0) as HasMatch
from (select IF(start_range<value and end_range>value, true, false ) as value
from XYZ having value =1) as MatchTable
DEMO

MySQL variable in WHERE clause

I need a query that find the recommended TV shows for an user, based on the TV Shows he is following.
Do to this I have the following tables:
the table Progress that contains wich show the user is following and the percentage of seen episodes (to solve this problem we can assume I have only one user in the database)
the table Suggested that contains _id1,_id2 and value (value is the strength of the connections between the show with id=_id1 and the show with id=_id2: the more value is great, the more the shows have something in common).
Note that in this table applies the commutative property, so the strength of the connection between id1 and _id2 is the same of _id1 and _id2. Moreover there aren't two rows such as ROW1._id1=ROW2._id2 AND ROW1._id2 = ROW2._id1
the table ShowCache that contains the details about a TV Show, such as name etc..
The following query is what I'm trying to do, but the result is an empty set:
SET #a = 0; //In other tests this line seem to be necessary
SELECT `ShowCache`.*,
(SUM(value) * (Progress.progress)) as priority
FROM `Suggested`,`ShowCache`, Progress
WHERE
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND #a:=_id1)//There is a best way to set a variable here?
OR
(_id1 = Progress.id AND _id2 NOT IN (SELECT id FROM Progress) AND #a:=_id2))
AND `ShowCache`._id = #a //I think that the query fails here
GROUP BY `ShowCache`._id
ORDER BY priority DESC
LIMIT 0,20
I know the problem is related to the usage of variables, but I can't solve it. Any help is really appreciated.
PS: the main problem is that (because of the commutative propriety), without variables I need two queries, wich takes about 3 secs to begin executed (the query is more complex than the above). I'm really trying to make a single query to do this task
PPS: I tied also with an XOR operation, that results in an infinite loop?!?!? Here's the WHERE clause I tried:
((_id2=Progress.id AND #a:=_id1) XOR (_id1=Progress.id AND #a:=_id2)) AND `ShowCache`._id = #a
EDIT:
I come up with this WHERE conditions without using any variable:
(_id2 = Progress.id OR _id1 = Progress.id)
AND `ShowCache`._id = IF(_id2 = Progress.id, _id1,_id2)
AND `ShowCache`._id NOT IN (SELECT id FROM Progress)
It works, but it is very slow.
Your attempt to use xor is clever. If you want to get the nonmatching value you want to use bitwise XOR which is ^
Progress.id ^_id1 ^ _id2
3 ^ 2 ^ 3 = 2
2 ^ 2 ^ 3 = 3
You can use this trick to setup a join and really simplify your query (eliminate the OR's and NOT IN's and do it in one query without variables.)
select users.name as username, showcache.name as show_name,
sum(progress * value) as priority from users
inner join progress on users.id = progress.user_id
inner join suggested on progress.show_id in (suggested.id_1, suggested.id_2)
inner join showcache on showcache.id =
(suggested.id_1 ^ suggested.id_2 ^ progress.show_id)
where showcache.id not in
(select show_id from progress where user_id = users.id)
group by showcache.id
order by priority desc;
I also setup a fiddle to demonstrate it:
http://sqlfiddle.com/#!2/2dcd8/24
To break it down. I created a users table with a single user (but the solution will work with multiple users.)
The select and join to progress is straightforward. The join to suggested uses IN as an alternative to writing it with OR
The join to showcache is where the bitwise XOR happens. One of the id's links up to the progress.show_id and we want to use the other one.
It does include a not in to exclude shows already watched from the results. I could have changed it to not exists? but it seems clearer this way.
You're setting #a's value twice within the where clause, meaning that the query is actually boiling down to:
...
WHERE ... AND `ShowCache`._id = _id2
MySQL evalutes variable assignments in a first-encountered order, so you should leave #a constant until the END of the clause, then assign a new value, e.g
mysql> set #a=5;
mysql> select #a, #a+1, #a*5, #a := #a + 1, #a;
+------+------+------+--------------+------+
| #a | #a+1 | #a*5 | #a := #a + 1 | #a |
+------+------+------+--------------+------+
| 0 | 1 | 0 | 1 | 1 |
| 1 | 2 | 5 | 2 | 2 |
| 2 | 3 | 10 | 3 | 3 |
+------+------+------+--------------+------+
Note that #a's value in the first 3 columns remains constant, UNTIL mysql reaches the #a := #a +1, after which #a has a new value
So perhaps your query should be
set #a = 0;
select #temp := #a, ..., #a := _id2
where
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND #temp =_id1)
...
etc...

Counting total and true condition lines

How to count the number of lines in a table and the number of lines where a certain condition is true without resorting to subselects like this:
create table t (a integer);
insert into t (a) values (1), (2), (null);
select
(select count(*) from t) as total_lines,
(select count(*) from t where a = 1) as condition_true
;
total_lines | condition_true
-------------+----------------
3 | 1
select count(*) as total_lines, count(a = 1 or null) as condition_true
from t
;
total_lines | condition_true
-------------+----------------
3 | 1
It works because:
First while count(*) counts all lines regardless of anything, count(my_column) will count only those lines where my_column is not null:
select count(a) as total
from t
;
total
-------
2
Second (false or null) returns null so whenever my condition is not met it will return null and will not be counted by count(condition or null) which only counts not nulls.
Use SUM(condition)!
select
count(*) as total_lines,
sum(a = 1) as condition_true
from t
See it working here.
This works because in mysql, true is 1 and false is 0, so the sum() of a condition will add 1 when it's true and 0 when it's false - which effectively counts the number of times the condition is true.
Many people falsely believe you need a case statement, but you don't with mysql (you do with some other databases)
this can be easily done using a condition inside count. I don't know if its the optimized method of doing it but it gets the work done
you can do it as follows
select count(*) as total_lines, COUNT(CASE WHEN a = 1 THEN 1 END) as condition_true from t
you can check it here
sqlFiddle

How to use result of an subquery multiple times into an query

A MySQL query needs the results of a subquery in different places, like this:
SELECT COUNT(*),(SELECT hash FROM sets WHERE ID=1)
FROM sets
WHERE hash=(SELECT hash FROM sets WHERE ID=1)
and XD=2;
Is there a way to avoid the double execution of the subquery (SELECT hash FROM sets WHERE ID=1)?
The result of the subquery always returns an valid hash value.
It is important that the result of the main query also includes the HASH.
First I tried a JOIN like this:
SELECT COUNT(*), m.hash FROM sets s INNER JOIN sets AS m
WHERE s.hash=m.hash AND id=1 AND xd=2;
If XD=2 doesn't match a row, the result is:
+----------+------+
| count(*) | HASH |
+----------+------+
| 0 | NULL |
+----------+------+
Instead of something like (what I need):
+----------+------+
| count(*) | HASH |
+----------+------+
| 0 | 8115e|
+----------+------+
Any ideas? Please let me know! Thank you in advance for any help.
//Edit:
finally that query only has to count all the entries in an table which has the same hash value like the entry with ID=1 and where XD=2. If no rows matches that (this case happend if XD is set to an other number), so return 0 and simply hash value.
SELECT SUM(xd = 2), hash
FROM sets
WHERE id = 1
If id is a PRIMARY KEY (which I assume it is since your are using a single-record query against it), then you can just drop the SUM:
SELECT xd = 2 AS cnt, hash
FROM sets
WHERE id = 1
Update:
Sorry, got your task wrong.
Try this:
SELECT si.hash, COUNT(so.hash)
FROM sets si
LEFT JOIN
sets so
ON so.hash = si.hash
AND so.xd = 2
WHERE si.id = 1
I normally nest the statements like the following
SELECT Count(ResultA.Hash2) AS Hash2Count,
ResultA.Hash1
FROM (SELECT S.Hash AS Hash2,
(SELECT s2.hash
FROM sets AS s2
WHERE s2.ID = 1) AS Hash1
FROM sets AS S
WHERE S.XD = 2) AS ResultA
WHERE ResultA.Hash2 = ResultA.Hash1
GROUP BY ResultA.Hash1
(this one is hand typed and not tested but you should get the point)
Hash1 is your subquery, once its nested, you can reference it by its alias in the outer query. It makes the query a little larger but I don't see that as a biggy.
If I understand correctly what you are trying to get, query should look like this:
select count(case xd when 2 then 1 else null end case), hash from sets where id = 1 group by hash
I agree with the other answers, that the GROUP BY may be better, but to answer the question as posed, here's how to eliminate the repetition:
SELECT COUNT(*), h.hash
FROM sets, (SELECT hash FROM sets WHERE ID=1) h
WHERE sets.hash=h.hash
and sets.ID=1 and sets.XD=2;

Change results in mysql query

I would like to manipulate the result I get from a query.
I have a set of 2.5m rows and there are 10 different ID's for a status. These statusses are not mapped in another table but I would like to manipulate the result I get in SQLyog.
What I would like to do is:
Count(Id) | Status
------------------
500.000 | 1
750.000 | 2
convert into a result
Count(Id) | Status
-------------------
500.000 | Initial order
750.000 | Cancelled
Can this be done in the query? Note that I'm not using PHP or a browser to display the results.
select
count(*) as TotalRecs,
case status
when 1 then "Initial Order"
when 2 then "Cancelled "
when 3 then "whatever "
else "all others "
end case as WordStatus
from
YourTable
group by
2
You can either inline it in a case statement
select COUNT(id),
case status
when 1 then 'initial order'
when 2 then 'cancelled'
# without an else, the rest go to NULL
end status
from tbl
group by status # yes, just on status
Or I would strongly encourage you to create a reference table for this
Tbl Status contains 2 columns ID and Description
select COUNT(tbl.id), status.description
from tbl
LEFT join status on status.id = tbl.status
group by status.description