SQL query to implement multiple WHERE condition on same column - mysql

I have two tables, tbl1 and tbl2 as below:
CREATE TABLE tbl1 (`uid` int);
INSERT INTO tbl1 (`uid`)
VALUES
(100),
(200),
(300),
(400);
CREATE TABLE tbl2 (`id` int, `uid` int, `status` int);
INSERT INTO tbl2 (`id`, `uid`, `status`)
VALUES
(1, 100, 0),
(2, 100, 1),
(3, 100, 2),
(4, 100, 4),
(5, 200, 0),
(6, 200, 1),
(7, 300, 0),
(8, 300, 3),
(9, 300, 4),
(10, 400, 1),
(11, 400, 2);
SQLFIDDLE:
http://sqlfiddle.com/#!2/1a6c20/13
Problem:
I want to join these two tables.
The result should show the rows having tbl2.status = 0 but not having tbl2.status = 1.
This is the SQL query which I'm trying to run:
SELECT DISTINCT tbl1.uid, tbl2.id, tbl2.status
FROM tbl1
INNER JOIN tbl2 ON (tbl1.uid = tbl2.uid)
WHERE tbl2.status = 0
OR tbl2.status <> 1;
CORRECT expected result is: 7, 300, 0.
Here, uid=300 has a row with status=0 and this uid=0 has no row with status=1. So this is the expected result that I want.
uid=100 has both status=0 and status=1, so this is not the required result.
uid=200 also has both status=0 and status=1 so this is not the required result.
uid=400 does not have status=0, this is not the required result.
Help please!!!

You need to select uids with status=0 but not the ones that appear in your table also with status=1. So you need to exclude them from the result set. You need one more condition in your where clause to have the expected result. This can be done by using NOT IN.
Try the following query
SELECT tbl1.uid, tbl2.id, tbl2.status
FROM tbl1
INNER JOIN tbl2 ON (tbl1.uid = tbl2.uid)
WHERE tbl2.status = 0
and tbl2.uid NOT IN (SELECT uid from tbl2 where status=1);

you can use NOT EXISTS clause
SELECT DISTINCT T1.uid, T2.id, T2.status
FROM tbl1 T1
INNER JOIN tbl2 T2 ON (T1.uid = T2.uid)
WHERE T2.status = 0
AND NOT EXISTS ( SELECT 1 FROM tbl2 T22
where T2.uid = T22.uid
and T22.status =1 )

There is a logic error with the OR in the WHERE clause.
The clause WHERE tbl2.status = 0 produces the desired result:
(7, 300, 0)
The clause OR tbl2.status <> 1 produces
(7, 300, 0)
(8, 300, 3)
(9, 300, 4)
Since this is an OR the union is taken, and you get all three tuples.
People new to SQL often find OR to be tricky. I used to keep truth tables near me when an unexpected result confused me.

Remove
OR tbl2.status <> 1
It is illogical (if the column equals 0 then it can't equal 1) and confuses the query.
If you want all unique uids where status equals 0, but never equals 1, then use a subquery, with the AND logic;
WHERE tbl2.status = 0
AND tbl2.uid NOT IN (SELECT uid FROM tbl2 WHERE status=1)
This selects all the rows where status equals 0, and then removes the rows where the same uid has a status that equals 1. This will give you the expected result you gave in the question.
If you want all rows except those where status equals 1, use;
WHERE tbl2.status <> 1
Which gives you exactly the same result as the current query, the tbl2.status = 0 is irrelevant.

Putting OR doesn't make sense, just remove the OR part and Try this:
SELECT DISTINCT tbl1.uid, tbl2.id, tbl2.status
FROM tbl1
INNER JOIN tbl2 ON (tbl1.uid = tbl2.uid)
WHERE status = 0;

Related

get rows from a table where value of field x is maximum

I have two tables myTable and myTable2 in a mysql database:
CREATE TABLE myTable (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
number INT,
version INT,
date DATE
) ENGINE MyISAM;
INSERT INTO myTable
(`id`, `number`, `version`, `date`)
VALUES
(1, '123', '1', '2016-01-12'),
(2, '123', '2', '2016-01-13'),
(3, '124', '1', '2016-01-14'),
(4, '124', '2', '2016-01-15'),
(5, '124', '3', '2016-01-16'),
(6, '125', '1', '2016-01-17')
;
CREATE TABLE myTable2 (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
myTable_id INT
) ENGINE MyISAM;
INSERT INTO myTable2
(`id`, `myTable_id`)
VALUES
(1, 1),
(2, 1),
(3, 2),
(4, 2),
(5, 3),
(6, 3),
(7, 4),
(8, 4),
(9, 4),
(10, 5),
(11, 6)
;
The field myTable2.myTable_id is a foreign key of myTable.Id.
I would like to get all the rows from myTable where myTable2.myTable_id = myTable.Id and the value of the field version in myTable is the maximum for every corresponding value for the field number in myTable.
I tried something like this:
SELECT
*
FROM
myTable,
myTable2
WHERE
myTable.version = (SELECT MAX(myTable.version) FROM myTable)
But the above query does not return the correct data. The correct query should output this:
Id number version date
2 123 2 2016-01-13
5 124 3 2016-01-16
6 125 1 2016-01-17
Please help!
One way to do this is to get the max version for each number in myTable in a derived table and join with that:
SELECT DISTINCT
m.*
FROM
myTable m
JOIN
myTable2 m2 ON m.id = m2.myTable_id
JOIN
(
SELECT number, MAX(version) AS max_version
FROM myTable
GROUP BY number
) AS derived_table
ON m.number = derived_table.number
AND m.version = derived_table.max_version
With your sample data this produces a result like this:
id number version date
6 125 1 2016-01-17
5 124 3 2016-01-16
2 123 2 2016-01-13
your Query is logically wrong. Here is the correct one
SELECT
*
FROM
myTable,
myTable2
WHERE
(myTable.version,myTable.number) in
(SELECT MAX(myTable.version),number FROM myTable group by number)
and myTable.id=myTable2.id
Here is the sqlfiddle http://sqlfiddle.com/#!9/74a67/4/0
This is the query posted for the previous edited question
SELECT * FROM myTable
inner join myTable2 on myTable.id = myTable2.mytable_id
WHERE (version, number) in
(SELECT MAX(version), number FROM myTable group by number)
Try this solution with using subquery simply as:
# Selecting desired result..
SELECT t1.id, t1.number, t1.version, t1.date
FROM myTable As t1 JOIN
# subquery to select max version and its corresponding
# number form myTable
(SELECT number, max(version) As max_ver FROM myTable
GROUP BY number
) As t2 ON t1.number = t2.number and t1.version = t2.max_ver
# Now checking for foreign key..
WHERE t1.id IN (SELECT mytable_id FROM myTable2);
Was it helpful..

Get maximum id if there are parent id otherwise get all results

I have a table and having the following data
CREATE TABLE IF NOT EXISTS `tbl_ticket` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL,
`ticket_title` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
--
-- Dumping data for table `tbl_ticket`
--
INSERT INTO `tbl_ticket` (`id`, `parent_id`, `ticket_title`) VALUES
(1, 0, 'tyty'),
(2, 0, 'testing'),
(3, 0, 'test from ticket'),
(4, 0, 'test ticket'),
(5, 0, 'test ticket'),
(6, 0, 'test ticket'),
(7, 0, 'test ticket'),
(8, 5, 'test ticket'),
(9, 0, '1 Ticket'),
(10, 0, '2Ticket'),
(11, 2, 'ticket2'),
(12, 2, 'ticket1'),
(13, 0, 'title 1234'),
(14, 0, 'titles 1234'),
(15, 14, 'sample 1234');
I need to return all rows where id is not present in parent id from the table.
Also if id is present in the parent_id column, I want to get the row having the highest id which matches the parent_id.
i.e. I need to return rows with id 1, 3,4,6,7,8,9,10, 12,13, 15.
I tried this sql
SELECT `id` , `parent_id`
FROM `tbl_ticket`
WHERE id NOT
IN (
SELECT parent_id
FROM tbl_ticket
)
but it returns value 11 also, instead it should return 12 which is the row having highest id with parent_id =2
Assuming the 5 in your expected output is a typo, as 5 appears in the parent_id field for id=8, you can get your result by the union of two simple queries.
select t1.id
from tbl_ticket t1
where not exists (
select 1 from tbl_ticket
where parent_id = t1.id
)
and parent_id = 0
union all
select max(id)
from tbl_ticket
where parent_id <> 0
group by parent_id
order by id asc
Fiddle here
The query is in two parts. the first part gets all the tickets that are not present in another tickets parent_id field, and which themselves do not have a parent (parent_id = 0).
The second part of the query looks at those tickets that DO have a parent (parent_id <> 0), and for each group of tickets that share the same parent_id, selects the one with the max id.
The results are then combined with a union to give a single result set. Since the two result sets are mutually exclusive, we can use union all to skip over the duplicate check.
If I understand correctly, you can do this with not exists rather than combining two separate queries. The advantage is that no duplicate elimination is needed (as is needed when you use union):
select t.*
from tbl_ticket t
where not exists (select 1
from tbl_ticket t2
where t2.parent_id = t.id
) or
not exists (select 1
from tbl_ticket t2
where t2.parent_id = t.id and t2.id > t.id
);
The first gets all rows that have no parents. The second gets all rows with the maximum id for a parent.
For best performance, you want an index on tbl_ticket(parent_id, id).

two select queries with different where clause on same table

i have a table follower and following count..
want to get the count of both in one stored procedure.. is it possible to have two select queries with different where condition on same table possible?
CREATE TABLE Table1
([val1] int, [val2] int, [val3] int, [val4] int, other int)
;
INSERT INTO Table1
([val1], [val2], [val3], [val4], other)
VALUES
(1, 26, 13, 1, 1),
(2, 13, 26, 1, 1),
(3, 10, 26, 1, 1),
(4, 26, 13, 1, 1),
(5, 14, 26, 1, 1)
;
MY select queries
(select count(*) as following_count from table1 where val2=26)
(select count(*) as follower_count from table1 where val3=26)
SQL FIDDLE LINK
Why don't you fire both statement using UNION ALL ?
See: http://dev.mysql.com/doc/refman/5.1/de/union.html
SO:
SELECT COUNT(*) AS following_count FROM table1 WHERE val2=26
UNION ALL
SELECT COUNT(*) AS following_count FROM table1 WHERE val3=26
returns two rows with 2 numbers in 1 query.
In two columns do this:
SELECT
(SELECT COUNT(*) AS following_count FROM table1 WHERE val2=26) col1
, (SELECT COUNT(*) AS following_count FROM table1 WHERE val3=26) col2
You could do this:
SELECT
SUM(CASE WHEN val2=26 THEN 1 ELSE 0 END) AS following_count,
SUM(CASE WHEN val3=26 THEN 1 ELSE 0 END) AS follower_count
FROM
table1
Just add semicolon to your statements...
(select count(*) as following_count from table1 where val2=26);
(select count(*) as follower_count from table1 where val3=26);

MySQL: find IDs with constatnly increasing values

I have the following table:
create table my_table
(
SubjectID int,
Date Date,
Test_Value int
);
insert into my_table(SubjectID, Date, Test_Value)
values
(1, '2014-01-01', 55),
(1, '2014-01-05', 170),
(1, '2014-01-30', 160),
(2, '2014-01-02', 175),
(2, '2014-01-20', 166),
(2, '2014-01-21', 160),
(3, '2014-01-05', 70),
(3, '2014-01-07', 75),
(3, '2014-01-11', 180)
I want to find IDs with constantly increasing Test_Value over time. In this example, only SubjectID 3 satisfies that condition. Could you write the code to find this out? Thanks for your help as always.
SELECT *
FROM my_table o
WHERE NOT EXISTS (
SELECT null
FROM my_table t1
INNER JOIN my_table t2 ON t2.Date > t1.Date AND t2.Test_Value < t1.Test_Value AND t1.SubjectID = t2.SubjectID
WHERE t1.SubjectID = o.SubjectID
)
The inner query would select all the entities that DO VIOLATE the requirements: they have later dates with least values. Then the outer select entities that do not match ones from the inner query.
SQLFiddle: http://www.sqlfiddle.com/#!2/1a7ba/12
PS: presumably if you only need an id - use SELECT DISTINCT SubjectID
If the values are not monotonically increasing, then there is at least one case where adjacent values decrease. Hence, you can reduce this problem to just looking at the previous value:
select t.SubjectId
from (select t.*,
(select TestValue
from table t2
where t2.SubjectId = t.SubjectId and
t2.Date < t.Date
order by t2.Date desc
limit 1
) as prev_Test_value
from table t
) t
group by t.SubjectId
having coalesce(sum(Test_Value < prev_Test_value), 0) = 0;

SELECT statement testing max values

I'm trying to get the ID where the Upper value is less than/equal to a given value.
myTable
(`ID`, `Lower`, `Upper`)
(1, 1, 9),
(2, 10, 49),
(3, 50, 99),
(4, 100, 499),
(5, 500, 999),
(6, 1000, 4999),
(7, 5000, 9999);
I've tried:
SELECT ID
FROM myTable
WHERE Lower>=3 AND Upper<=3;
and
SELECT ID
FROM myTable
WHERE Upper<=3
ORDER BY ID DESC;
and
SELECT ID
FROM myTable
GROUP BY ID HAVING MAX(Upper)<=3
ORDER BY MAX(Upper);
and
SELECT *
FROM myTable t1
WHERE t1.Upper <= (
SELECT (MAX(t2.Upper))
FROM myTable t2
);
all of which return empty rows.
The option:
SELECT ID
FROM myTable
WHERE Upper<=10
ORDER BY ID DESC;
works where the test value is greater than 9...
Can anyone suggest a solution that might work?
The syntax on
SELECT ID
FROM myTable
WHERE Upper<=3
ORDER BY ID DESC;
Works just fine on MYSQL? double check for spelling errors or syntactical errors perhaps?
If you want to return NULL where there is no match instead of "no rows", you can try something like:
SELECT max(ID)
FROM myTable
WHERE Upper<=3;
I think I get it now - you want the id of the maximum Upper value, as long as it is less than or equal to your "test" value. Is that correct?
select id
from myTable
where Upper <= X
order by Upper desc
LIMIT 1;
So if X = 9 you would get ID: 1
If X = 10 you would also get ID: 1
If X = 163 you would get ID: 3