SQL - how to select rows that do not contain a certain ID - mysql

So I have the table flag_counts with the following columns:
flag_id content_id
1 10
2 10
2 11
and the following query
SELECT flag_id, content_id FROM flag_counts
WHERE flag_id != 1
and of course it returns
flag_id content_id
2 10
2 11
How can I change my query so that it returns all content_ids that were not flagged with "1". In this example, I would like the query to return only the last row of the table since the content_id "10" was flagged once with "1".

Group by the content_id and take only those having zero records with flag_id = 1
SELECT content_id
FROM flag_count
GROUP BY content_id
HAVING sum(flag_id = 1) = 0

SELECT whatever
FROM flag_counts
WHERE content_id NOT IN (
SELECT content_id
FROM flag_counts
WHERE flag_id = 1
)
or via JOIN
SELECT DISTINCT c1.*
FROM flag_counts c1
LEFT JOIN flag_counts c2
ON c1.content_id = c2.content_id and c2.flag_id = 1
WHERE c2.content_id IS NULL;

This addresses the question: How to change my query so that it returns all content_ids that were not flagged with "1"? The "clarification" is actually more confusing, because SQL tables represent unordered sets, so there is no "last" row.
If you have a separate table of content ids, then the fastest approach might be:
select c.*
from contents c
where not exists (select 1
from flag_count fc
where fc.content_id = c.content_id and flag_id = 1
);
For this, you would want an index on flag_count(content_id, flag_id).
If you use flag_count instead of contents, then you might get duplicates.

One of the following method can be used to solve this.
SELECT DISTINCT a.content_id
FROM
flag_counts a
LEFT JOIN flag_counts b
ON (a.content_id = b.content_id AND b.flag_id = 1)
WHERE b.content_id IS NULL;
SELECT DISTINCT a.content_id FROM flag_counts a
WHERE NOT EXISTS (SELECT 1 FROM flag_counts b WHERE a.content_id = b.content_id AND b.flag_id = 1)

Related

Need to find specific records from two tables with SQL query

I've two tables
magento_customerbalance -mcb
column -
1. balance_id
2. customer_id
3. website_id
4. amount
5. base_currency_code
customer_entity_varchar -cev
column -
1. value
2. attribute_id
3. entity_id
4. value
I've tried to find customer_id from mcb which does not have cev.attribute_id 5 with the following SQL queries
Query #1:
SELECT COUNT(mcb.customer_id)
FROM magento_customerbalance mcb;
Results :
total customer from mcb =121
Query #2:
SELECT mc.customer_id
FROM magento_customerbalance mc
INNER JOIN customer_entity_varchar cev ON cev.entity_id = mc.customer_id
WHERE cev.attribute_id = 5;
Results :
total customers from mcv with attribute id 5 = 100
121 -100 =21
customer who does not have attribute id 5 = 21
How we can get these 21 mcb.customer_id records with a SQL query?
In cev table there are multiple attribute ids for same customer.
Use the not exists operator with a correlated subquery as the following:
SELECT mcb.customer_id /* add other columns as needed */
FROM magento_customerbalance mcb
WHERE NOT EXISTS
(
SELECT 1 FROM customer_entity_varchar cev
WHERE cev.entity_id = mcb.customer_id AND
cev.attribute_id = 5
)
And if you want only customer_ids which have an entity_id in the cev table add this condition:
AND EXISTS
(
SELECT 1 FROM customer_entity_varchar cev
WHERE cev.entity_id = mcb.customer_id
)
See demo
Did you tried not equal to 5, !=5 ?
SELECT mc.customer_id FROM magento_customerbalance mc inner join customer_entity_varchar
cev on cev.entity_id = mc.customer_id
where cev.attribute_id != 5 OR cev.attributee IS NULL;

How to get records from two tables with multiple where conditions

I have a two tables one is Userregistration and second is user_verificationcode from which i have to get only those record whose email and mobile status are 1.Below are my table structure
Userregistration table
........................................
id fullname mobile_no email
.........................................
5 varun 12344567 abc#gmail
6 nitin 12345678 def#gmail
user_verificationcode
.............................................
id user_id codetype status
............................................
1 5 email 0
2 5 mobile 1
3 6 email 1
4 6 mobile 1
I want this kind of output
........................................
id fullname mobile_no email
.........................................
6 nitin 12345678 def#gmail
For this i have used below query but its not working i am not getting how to achieve this.
SELECT * FROM Userregistration
INNER JOIN user_verificationcode ON Userregistration.`id`=user_verificationcode.`user_id`
where user_verificationcode.`codetype`='email'
and user_verificationcode.`status`='1'
and user_verificationcode.`codetype`='mobile'
and user_verificationcode.`status`='1'
SELECT r.*
FROM Userregistration r
INNER JOIN user_verificationcode ve ON r.id = ve.user_id
and ve.codetype = 'email'
and ve.status = 1
INNER JOIN user_verificationcode vm ON r.id = vm.user_id
and vm.codetype = 'mobile'
and vm.status = 1
or
SELECT *
FROM Userregistration
where id in
(
select user_id
from user_verificationcode
group by user_id
having sum(codetype = 'email' and status = 1) > 0
and sum(codetype = 'mobile' and status = 1) > 0
)
You probably want to return only Userregistration fields, since you already know the info contained in user_verificationcode table. In this case you can use the following query:
SELECT t1.*
FROM Userregistration AS t1
JOIN (
SELECT user_id
FROM user_verificationcode
WHERE codetype IN ('mobile', 'email')
GROUP BY user_id
HAVING COUNT(DISTINCT codetype) = 2 AND SUM(status <> 1) = 0
) AS t2 ON t1.id = t2.user_id
You may would like to do something like this
SELECT Userregistration.id, Userregistration.fullName, Userregistration.mobile_no,
Userregistration.email FROM Userregistration
INNER JOIN user_verificationcode
ON Userregistration.id=user_verificationcode.user_id
WHERE user_verificationcode.codetype='email' AND user_verificationcode.status = 1
SELECT Userregistration.id,
Userregistration.fullName,
Userregistration.mobile_no,
Userregistration.email
FROM Userregistration
INNER JOIN user_verificationcode ON
Userregistration.id=user_verificationcode.user_id AND
user_verificationcode.status=1
WHERE user_verificationcode.codetype='email' AND
user_verificationcode.codetype='mobile'

mysql SELECT EXISTS on multiple tables

Have tables: person,person_ip
Both tables have pid column as a primary key, in table person there is column state_id, in table person_ip there is column ip.
Want to discover if specified IP address is assigned to person with state_id is not equal to 2. But always got result 1, even if state_id is 0, 1 or 2. Always got 0 only if ip address is not listed at all. What am I doing wrong?
SELECT EXISTS (
SELECT person_ip.PID
FROM person_ip,person
WHERE person.PID=person_ip.PID
AND person.state_id NOT IN (2)
AND person_ip.ip='10.11.12.13'
)
this seems like a simple join.. unless i'm missing something
select person.*
from person
inner join person_ip
on person.pid = person_ip.pid
where person.state_id <> 2
and person_ip.ip_address = '10.0.0.1'
If you want to exclude the ip_address if it has been assigned to any user with state = 2, even if it has also been assigned to a user without state = 2, then try:
select max(i)
from (
select *
from (
select 1 as i
from dual
where not exists (
select 1
from person p
inner join person_ip pi
on p.pid = pi.pid
where p.state_id = 2
and pi.ip_address = '10.0.0.1'
)
) q
union
select 0
) qq
(dual is a system table that can be used as a sort of stub table)
here's a fiddle showing both versions
update after some actual sleep
Okay, so the above query is a little.. out there. Back in the real world, this one is probably more appropriate:
select count(case when p1.state_id = 2 then 1 end)
from person p1
inner join person_ip pi1
on p1.pid = pi1.pid
where pi1.ip_address = '10.0.0.1'
group by pi1.ip_address;
This will return 1 or more if your ip_address has been used by someone with a state_id of 2, and 0 if it has never been used by someone with a state_id of 2.
It will return nothing if the ip has never been used.
this fiddle has all three of the above queries.
SELECT IF(COUNT(*)>0,1,0)
FROM person
INNER JOIN person_ip
ON person.pid = person_ip.pid
AND person_ip.ip_address = '10.0.0.1'
WHERE person.state_id <> 2

MySQL One to Many remove specific 'many'

I have a database with a one to many relationship (venues, with associated categories) like so:
venue_id | venue_name
---------------------
1 | venue1
2 | venue2
and categories
venue_id | category_id
---------------------
1 | 5
2 | 7
1 | 8
2 | 5
I want to show all venues that HAVE category_id of 5, but dont have category_id of 7 and 8. I tried using a join like so:
SELECT distinct(`venue_to_category`.`venue_id`),`venue_name`
FROM `venue_to_category` INNER JOIN `venues`
ON `venues`.venue_id = `venue_to_category`.venue_id
WHERE `category_id` != 7
AND `category_id` != 8
AND `category_id` = 5
But it is not returning the correct results (in fact I am unsure the results it is returning)
2 Things in your case
Get data where category_id = 5 and not 7 or 8
Get data where category_id = 5 and not both 7 and 8
For the first one you can use
select
v.venue_id,
v.venue_name
from venues v
join categories c on c.venue_id = v.venue_id
where c.category_id = 5
AND NOT EXISTS
(
select 1 from categories c1 where v.venue_id = c1.venue_id
AND c1.category_id in (7,8)
);
For the 2nd one
select
v.venue_id,
v.venue_name
from venues v
join categories c on c.venue_id = v.venue_id
where c.category_id = 5
AND NOT EXISTS
(
select 1 from categories c1 where v.venue_id = c1.venue_id
AND c1.category_id in (7,8) having count(*) = 2
);
DEMO
When doing a search function of your site. Match and Against is better than Like sql statement. The field must be set to FullText match the term on the field:
SELECT vc.venue_id, venue_name FROM venue_to_category vc, venues v WHERE MATCH(category_id) AGAINST('-7 -8 +5');
You can also use the IN BOOLEAN MODE to allow operators in the sql statement. eg. ...
MATCH(category_id) AGAINST('-7 -8 +5' IN BOOLEAN MODE) ...
(-) minus sign that means nothing should match '-7' '-8'
(+) the word must be present in the match.
There are many other operators to be used. Refer to this page for more operator and explanation
Try
SELECT distinct `venue_to_category`.`venue_id` ,`venue_name`
FROM `venue_to_category` INNER JOIN `venues`
ON `venues`.venue_id = `venue_to_category`.venue_id
WHERE `category_id` <> 7
AND `category_id` <> 8
AND `category_id` = 5
or
SELECT distinct `venue_to_category`.`venue_id` ,`venue_name`
FROM `venue_to_category` INNER JOIN `venues`
ON `venues`.venue_id = `venue_to_category`.venue_id
WHERE `category_id` NOT IN (7,8)
AND `category_id` = 5
Note: distinct is not a function. And for your example you could leave it out entirely, because there are no duplicate rows.
SELECT v.id, v.name
FROM venues v
JOIN venue_to_category vc
ON vc.venue_id=v.id
AND vc.category_id=5
WHERE NOT EXISTS (
SELECT 1
FROM venue_to_category vci
WHERE vci.venue_id = v.id
AND vci.category_id IN (7,8)
);

mysql converting multiple rows into columns in a single row

i have a details table with columns:
user_id int
code int
value int
And i want to build a summary table that looks like:
user_id int
valueA int
valueB int
In the details table, valueA would correspond to say, code 5, and valueB would correspond to say, code 6, so i'm looking for something like:
insert into summary (user_id,valueA,valueB) VALUES ( SELECT ??? from details );
The problem of course is that i'm looking at multiple rows from the "details" table to populate one row in the "summary" table.
Eg, if i had the following rows in details:
1 5 100
1 6 200
2 5 1000
2 6 2000
I want to end up with the following in the summary table:
1 100 200
2 1000 2000
Any ideas?
MySQL doesn't have PIVOT/UNPIVOT syntax, which leaves you to use a combination of GROUP BY and CASE expressions:
INSERT INTO SUMMARY
(user_id,valueA,valueB)
SELECT d.user_id,
MAX(CASE WHEN d.code = 5 THEN d.value ELSE NULL END),
MAX(CASE WHEN d.code = 6 THEN d.value ELSE NULL END),
FROM DETAILS d
GROUP BY d.user_id
insert into summary (user_id,valueA,valueB)
SELECT a.user_id, a.value, b.value
from details a
join details b on a.user_id = b.user_id
WHERE a.code = 5 and b.code = 6;
beware: you will end up with multiple summary columns if user_id+code is not unique.
EDIT:
insert into summary (user_id,valueA,valueB)
select u.user_id, ifnull(a.value,0), ifnull(b.value,0)
from (select distinct user_id from details /* where code in (5,6) */) u
left join details a on a.user_id = u.user_id and a.code = 5
left join details b on b.user_id = u.user_id and b.code = 6
If you have a manageable set of codes (say just 5 and 6) you could do something like this:
SELECT details.user_id, code5.value, code6.value
FROM details JOIN
(SELECT user_id, value FROM details WHERE code = 5) AS code5 USING(user_id)
JOIN
(SELECT user_id, value FROM details WHERE code = 6) AS code6 USING(user_id);
You may need to modify your JOINs depending on if your codes are not required as 1 to 1 relationship (i.e. LEFT JOINs).
If you have a large set of codes, I would look into a cursor runs a similar query above over a result set of your codes or using a different technology, (i.e. PHP script).