How do I fetch query results with multiple criteria? - mysql

I have a table like this
Table
-----
userid
fieldid
fieldvalue
where userid and fieldid are the primary key pair for this table.
I want to make an sql query that finds all users that have fieldvalue equal to something for a selected fieldid
For example, for the values
fieldid: 817
fieldvalue: 'yes'
I can have an sql query like:
select userid FROM table where (fieldid=817 AND fieldvalue='yes')
This query works fine.
However if i have a second or a third criterion, making the query
like this:
select userid
FROM table
where (fieldid=817 AND fieldvalue='yes')
AND (fieldid=818 AND fieldvalue='no')
returns an empty result but the conditions are satisfied in the
individual criterion.
Is there any way to correct this ?
update
i forgot to write down a use case (appologies)
userid, fieldid, fieldvalue
1 , 817, yes
1, 818, no
1, 825, yes
2, 817, yes
2, 818, yes
3, 829, no
for this table i want an sql query that finds the users that have the following conditions satisfied : The fieldid 817 has a value of yes and the fieldid 818 a value of no
Using the OR suggestions i had so far satisfied either the fieldid 817 to have a value of yes OR the fieldid 818 to have a value of no
I want both conditions to be satisfied. In the above the expected result will be
userid
1
and not
userid
1
2
Since userid 2 doesn't satisfy both conditions. Apologies for the confusion.

You should use an OR between your different criteria.
SELECT userid
FROM table
WHERE (fieldid=817 AND fieldvalue='yes')
OR (fieldid=818 AND fieldvalue='no')
The difference between using AND/OR
The AND operator displays a record if both the first condition and the
second condition is true.
The OR operator displays a record if either the first condition or the
second condition is true.
EDIT: Based on your comments you can do it the following way
select t1.userid
FROM temp t1
where (t1.fieldid=817 AND t1.fieldvalue='yes')
AND EXISTS (SELECT userid
FROM temp t
WHERE t.userid = t1.userid
AND fieldid=818
AND fieldvalue='no')
see a sqlfiddle with a working copy
or even this way
select t1.userid
FROM temp t1
left join temp t2
on t1.userid = t2.userid
where (t1.fieldid=817 AND t1.fieldvalue='yes')
AND t2.fieldid=818 AND t2.fieldvalue='no'
here is another sqlfiddle
if you had more fields that you wanted to join on, then you would do the following:
select t1.userid
FROM temp t1
left join temp t2
on t1.userid = t2.userid
left join temp t3
on t1.userid = t3.userid
where (t1.fieldid=817 AND t1.fieldvalue='yes')
AND (t2.fieldid=818 AND t2.fieldvalue='no')
AND (t3.fieldid=819 AND t3.fieldvalue='no')

Try using OR
select userid FROM table where (fieldid=817 AND fieldvalue='yes') OR(fieldid=818 AND fieldvalue='no')
Your query wanted the fieldid to be 817 and 818 which isn't possible.

You should use OR not AND in your WHERE clause. Check out this link for a quick-and-easy explanation.

Hi Please try OR in Place of AND
select userid FROM table where (fieldid=817 AND fieldvalue='yes') OR (fieldid=818 AND fieldvalue='no')
If you use AND then it will check if both conditions fieldid=817 AND fieldvalue='yes' ANd fieldid=818 AND fieldvalue='no' must be fulfilled but it is not possible. ANd when you will use OR operator between both conditions then it will give result having both conditions ..
thanks

you need to use it like:
select userid
FROM table
where fieldid in (817, 818) and fieldvalue in ('yes', 'no');

In addition to the many suggestions of using OR, which are entirely correct, you could also use IN (which might make the query more readable if it scales).
SELECT userid FROM table WHERE (fieldid, fieldvalue) IN (
(817, 'yes'),
(818, 'no' )
);
To find all userid that satisfy both conditions, you need to self-join table to itself:
SELECT userid
FROM table AS t1 JOIN table AS t2 USING (userid)
WHERE
(t1.fieldid = '817' AND t1.fieldvalue = 'yes')
AND (t2.fieldid = '818' AND t2.fieldvalue = 'no' )

Related

Creating new table which contains unique rows with conditions ; MySQL

I have a table with the following columns:
SessionID - contains actions within a session (1-10 rows per SessionID let's say)
ActionName - is the name of the action
Time - time action occurred
I need to return a new table, whose columns are the same, and contains only 1 row per SessionID IF the action's name is either "a" or "b".
That is, my new table should have a 1 row per SessionID which had the action "a" or "b".
I tried:
CREATE TABLE U_SessionID (
SELECT DISTINCT(SessionID) AS SessionID FROM test1)
;
I copy the unique sessions to a new table
SELECT U_SessionID.SessionID, test1.ActionName, test1.SessionID
FROM test1
INNER JOIN U_SessionID ON (SELECT SessionID
FROM test1
WHERE U_SessionID.SessionID = test1.SessionID AND (ActionName =
"a" OR ActionName = "b")
ORDER BY Time DESC
LIMIT 1);
But this code causes MySQL workbench to crash (timeout performing query), and I have no idea if it even works.
Sample data:
Can you think of a lighter query to run this?
Maybe a better approach would be:
take all rows with action "a" or action "b":
SELECT * FROM test1 WHERE ActionName = "a" OR ActionName = "b";
drop duplicates based on the SessionID only (no matter the time order)
Ideas for that?
Is the time unique for a session ID?
If so:-
SELECT U_SessionID.SessionID, test1.ActionName, test1.SessionID
FROM test1
INNER JOIN
(
SELECT SessionID
MAX(Time) AS MaxTime
FROM test1
WHERE ActionName IN ("a", "b")
GROUP BY SessionID
) sub0
ON test1.SessionID = sub0.SessionID
INNER JOIN U_SessionID
ON sub0.SessionID = U_SessionID.SessionID
AND sub0.MaxTime = U_SessionID.Time
If time isn't unique, but assuming the table has a unique column called id:-
SELECT U_SessionID.SessionID, test1.ActionName, test1.SessionID
FROM test1
INNER JOIN
(
SELECT SessionID
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY Time DESC), ',', 1) AS MaxId
FROM test1
WHERE ActionName IN ("a", "b")
GROUP BY SessionID
) sub0
ON test1.SessionID = sub0.SessionID
INNER JOIN U_SessionID
ON sub0.SessionID = U_SessionID.SessionID
AND sub0.MaxId = U_SessionID.id
EDIT
If you just want a random record for each session id then you could (ab)use the GROUP BY clause. I really do not like this idea as while it probably does work, it might well not work depending on the configuration of your MySQL database, and even if it does work someone might do an update that stops it working. Even then if it still works there is no garuntee that it will bring back a single real record, rather than a single rows whose columns are a mix of those from different rows.
So put here for completeness and to give you an option but I strongly advise against using it
SELECT U_SessionID.SessionID, test1.ActionName, test1.SessionID
FROM test1
INNER JOIN U_SessionID ON U_SessionID.SessionID = test1.SessionID
WHERE ActionName IN ("a" , "b")
GROUP BY U_SessionID.SessionID
If you want a simple solution that is more future proof then use my 2nd solution and remove the ORDER BY clause within the GROUP_CONCAT
You can change you query like below. Your subquery is unnecessary here.
SELECT U_SessionID.SessionID, test1.ActionName, test1.SessionID
FROM test1
INNER JOIN U_SessionID ON U_SessionID.SessionID = test1.SessionID
WHERE ActionName IN ("a" , "b")
ORDER BY `Time` DESC
LIMIT 1;

SQL OR Operator on different tables and column names

I know that I can use the OR SQL operator on the same column of a table like the following:
SELECT * FROM users WHERE last_name = 'Peter' OR last_name = 'Smith';
But the situation I have right now is that I'm trying to use the OR operator on two different tables (different column names). Is that possible? How can I achieve that in an SQL query?
And yes there is a foreign key column that links one table to the primary key column of the other table.
Thanks in advance for any help.
If the fields in the different tables have the same name, you can distinguish them with tablename.fieldname, if the tables have the same name (in different schemas), you can further qualify the names with schemaname.tablename.fieldname.
Of course, all tables referenced in the WHERE and SELECT clauses should be included in the FROM clause.
Note: If a table is aliased in the FROM, the alias should be used instead of the table name.
You cannot display (or use in WHERE conditions, etc...) fields from a table that not included in the FROM; however, you can use subqueries on those tables.
Examples:
...
FROM table1 AS t1
WHERE t1.field1 = somevalue
OR EXISTS (
SELECT *
FROM table2 AS t2
WHERE t2.somefield = someothervalue
)
...
or
SELECT t1.field1
, (SELECT t2.somefield FROM table2 AS t2 WHERE t2.anotherfield = somevalue LIMIT 1) AS t2Val
FROM table1 AS t1
...
Yes , it is possible
SELECT users.* FROM users,countries WHERE users.last_name = 'Peter' OR countries.name = 'mexico' AND users.idCountry=countries.id;

SQL Join 2 tables with almost same field

I need to join two tables in SQL. There are no common fields. But the one table have a field with the value krin1001 and I need it to be joined with the row in the other table where the value is 1001.
The idea behind the joining is i have multiple customers, but in the one table there customer id is 'krin1001' 'krin1002' and so on, in this table is how much they have sold. In the other table there customer is is '1001' '1002' and so on, and in this table is there name and adress and so on. So it will always be the first 4 charakters i need to strip from the field before matching and joining. It might not always be 'krin' i need it to work with 'khjo1001' also, and it still needs to join on the '1001' value from the other table.
Is that possible?
Hope you can help me.
You need to use substring:
ON SUBSTRING(TableA.Field, 5, 4) = TableB.Field
Or Right:
ON RIGHT(TableA.Field, 4) = TableB.Field
You can also try to use CHARINDEX function for join operation. If value from table1 contains value from table2 row will be included in result set.
;WITH table1 AS(
SELECT 'krin1001' AS val
UNION ALL
SELECT 'xxx'
UNION ALL
SELECT 'xyz123'
),
table2 AS(
SELECT '1001' AS val
UNION ALL
SELECT '12345'
UNION ALL
SELECT '123'
)
SELECT * FROM table1 AS t
JOIN table2 AS T2 ON CHARINDEX(T2.val, T.val) > 0
Use it as:
SELECT
*
FROM table t1
INNER JOIN table t2 ON RIGHT(t1.col1, 4) = t2.col1;

SQL select with multiple conditions on the same table

I have 2 tables in MySQL, the first one has 2 columns: ID and name, the second has 3 columns: firstTableId (foreign key on the first table), key, value.
I have the following rows in table 1:
1,Bob
2,Alice
3,Fred
I have the following rows in table 2:
1,age,20
1,gender,male
2,age,20
2,gender,female
3,age,18
3,gender,male
I would like to write a select query using only the last 2 columns on the second table (key and value) that returns only Bob form the first table, but I can't seem to figure it out.
Essentially I want to select from the first table all rows where, in the second table, we have key=age and value=20 for one row, and key=gender and value=male in another row. Can anyone point me in the right direction ? Manipulating table structure is not preferred as this is a simplified example and both "key" and "value" columns in the second table can be pretty much anything, it's not actually limited to "age" and "gender".
Thanks in advance.
You can do this with a self join like this:
select
*
from
table1 t1
inner join table2 age on t1.id = age.id
inner join table2 gender on t1.id = gender.id
where
(age.`key` = 'age' and age.value = 20)
and
(gender.`key` = 'gender' and gender.value = 'male')
An additional tactic you may want to try is a PIVOT query. Mysql doesnt have anything native to support pivot's, but there are several examples of how to do them.
You can see it working in this fiddle
Use two IN clauses (or two EXISTS clauses).
select *
from table1
where id in (select firstTableId from table2 where key = 'age' and value = '20')
and id in (select firstTableId from table2 where key = 'gender' and value = 'male');
With EXISTS:
select *
from table1
where exists (select * from table2 where key = 'age' and value = '20' and firstTableId = table1.firstTableId)
and exists (select * from table2 where key = 'gender' and value = 'male' and firstTableId = table1.firstTableId);

Select Pairs in MySQL

Have a table where certain rows come in couples which have a matching GUID. Just wondering how to SELECT all data from the table but ONLY if the rows exist as a couple with a matching GUID.
You can use a query like this:
SELECT *
FROM yourtable
WHERE GUID IN (SELECT GUID FROM yourtable GROUP BY GUID HAVING COUNT(*)=2)
The subquery will return all GUIDs that appears exactly twice, the outer query will return all rows associated to those GUIDs.
Please see fiddle here.
Try something like this:
SELECT t1.*
FROM
table t1
, table t2
WHERE
t1.guid = t2.guid
AND t1.id <> t2.id
;
table: your table name
id: some field that you know is different for both rows
Try
SELECT t.*
FROM Table1 t JOIN
(
SELECT guid
FROM Table1
GROUP BY guid
HAVING COUNT(*) = 2
) q ON t.guid = q.guid
Here is SQLFiddle demo