MySQL distinct count - mysql

abc table -
ID
---
1
2
3
xyz table -
abc_id | flag
--------------
1 | 0
1 | 1
2 | 0
3 | 0
3 | 0
I need the count of distinct abc_id where if flag = 1 for a particular abc_id, then that id shouldn't be counted.
In the above example, the count should be 2. Is there any way I can achieve that? Sorry if the question has been answered before or if it's something obvious. Thanks in advance ^^
EDIT: Basically I want the abc_id = 1 to be ignored in the count because one of it's flag = 1. I hope it's clear enough :|

The main issue was figuring out what you meant, but I'm pretty sure it's this. :o)
Count the distinct abc_ids, fully excluding the ids that have at least one row that was flagged. So id 1 is excluded, because it has a flag.
You can solve this with a not in condition, to exclude all ids that were flagged. After that, you can count the remaining rows, using count(distinct abc_id), to get the number of distinct ids.
select
count(distinct abc_id) as non_flagged_id_count
from
xyz x1
where
abd_id not in
(select x2.abc_id from xyz x2 where x2.flag = 1)

select count(distinct abc_id)
from xyz as x
left join (
select abc_id from xyz where flag = 1
) as y using (abc_id)
where y.abc_id is null
;

Related

Query database to obtain first unique value

I have a pretty simple table like this:
id | custom_id | answer
----------------------------------
1 | 123 | Answer 1
__________________________________
2 | 123 | Answer 2
__________________________________
3 | 422 | Answer 3
__________________________________
4 | 345 | Answer 2
__________________________________
5 | 992 | Answer 1
__________________________________
6 | 452 | No answer
__________________________________
What I am trying to do is count the number of Answer 1, Answer 2, etc. So, for the above data I would expect to get:
2 * Answer 1
2 * Answer 2
1 * Answer 3
Note, that anything that is No answer should be discarded.
However, further to the above, I want to take into account only one answer per custom_id, and this should be their first answer. So really, the output I expect to get for the above data should be:
2 * Answer 1
1 * Answer 2
1 * Answer 3
This is because we take only the first answer for custom_id = 123.
So far, I have made the following query:
select
answer,
count(*) as totalCount
from
" . DB_TABLE . "
where
answer <> 'No answer'
group by
custom_id
However, this seems to return the total counts (as I explained first), not taking into consideration that there should only be one per custom_id. I thought the group by would solve this issue, but this does not seem to be the case.
How can I achieve the results I am after?
Thanks
One approach, will be first to create a derived table with the IDs of the first answers for every custom_id and also filter those with values No answer (since you want to ignore they), like this:
SELECT
custom_id,
MIN(id) AS firstAnswerID
FROM
<table_name>
WHERE
answer <> "No Answer"
GROUP BY
custom_id
Then, we can join the original table with this previous one on the ID column (this will act like a filter for those that aren't first answers or have the No answer value), make a GROUP BY the answer column and count the numbers of each one. In summary, this will do what you want:
SELECT
t1.answer,
COUNT(*) AS NumTimes
FROM
<table_name> AS t1
INNER JOIN
( SELECT
custom_id,
MIN(id) AS firstAnswerID
FROM
<table_name>
WHERE
answer <> "No Answer"
GROUP BY
custom_id ) AS t2 ON t2.firstAnswerID = t1.id
GROUP BY
t1.answer
ORDER BY
NumTimes DESC
You can play with this here: DB Fiddle
Try to use this:
select answer, count(answer) as totalCount from " . DB_TABLE .
" where answer <> 'No answer' group by answer
You should count rows for every answer group, not for the entire table.

MySQL select query with AND condition on same columns of same table

I have a table like this
itemid | propertyname | propertyvalue
___________|______________|_______________
1 | point | 12
1 | age | 10
2 | point | 15
2 | age | 11
3 | point | 9
3 | age | 10
4 | point | 13
4 | age | 11
I need a query to select all items where age greater than 10 and point less than 12.
I tried
`select itemid from table where (propertyname="point" and propertyvalue < 12)
and (propertyname="age" and propertyvalue >10)`
It gives no results. How can I make it work?
you can use an inner join
SELECT
a.itemid
FROM
yourTable a
INNER JOIN
yourTable b
ON
a.itemid=b.itemid
AND a.propertyname='point'
AND b.propertyname='age'
WHERE
a.propertyvalue<12
AND b.propertyvalue>10
ok so in table a youre lookin for all items with the name point and a value smaller 12 and in table b youre looking for all items with the name age and a value greater 10. Then you only have to look for items, which are in both tables. For this you connect the two tables over the itemid. To connect tables you use the join. Hope this will help you to understand. If not ask again :)
To join a table to itself in the same query you can include the table twice in the FROM clause, giving it a different alias each time. Then you simply proceed with building your query as if you were dealing with two separate tables that just happen to contain exactly the same data.
In the query below the table example is aliased as a and b:
SELECT a.itemid
FROM example a, example b
WHERE a.itemid = b.itemid
AND a.propertyname = 'point'
AND a.propertyvalue < 12
AND b.propertyname = 'age'
AND b.propertyname > 10
Try It:
SELECT itemid FROM test_table WHERE propertyname="point" AND propertyvalue < 12 AND itemid IN(SELECT itemid FROM test_table WHERE propertyname="age" AND propertyvalue >10)
http://sqlfiddle.com/#!9/4eafc6/1
PLs Try this
select itemid from table where (propertyname="point" and propertyvalue < 12)
or (propertyname="age" and propertyvalue >10);
Here's one idea...
SELECT item_id
, MAX(CASE WHEN propertyname = 'point' THEN propertyvalue END point
, MAX(CASE WHEN propertyname = 'age' THEN propertyvalue END age
FROM a_table
GROUP
BY item_id
HAVING age+0 > 10
AND point+0 < 12;
You can use an inner join. Meaning, it's like you're going to work with 2 tables: the first one you're going to select the name="age" and val>10, and the second one is where you're going to select name="point" and val<12.
It's like you're creating an instance of your table that doesn't really exist. It's just going to help you extract the data you need at the same time.

MySQL intersection of two tables

I need to implement a function which returns all the networks the installation is not part of.
Following is my table and for example if my installation id is 1 and I need all the network ids where the installation is not part of then the result will be only [9].
network_id | installation_id
-------------------------------
1 | 1
3 | 1
2 | 1
2 | 2
9 | 2
2 | 3
I know this could be solved with a join query but I'm not sure how to implement it for the same table. This is what I've tried so far.
select * from network_installations where installation_id = 1;
network_id | installation_id
-------------------------------
1 | 1
2 | 1
3 | 1
select * from network_installations where installation_id != 1;
network_id | installation_id
-------------------------------
9 | 2
2 | 2
2 | 3
The intersection of the two tables will result the expected answer, i.e. [9]. But though we have union, intersect is not present in mysql. A solution to find the intersection of the above two queries or a tip to implement it with a single query using join will be much appreciated.
The best way to do this is to use a network table (which I presume exists):
select n.*
from network n
where not exists (select 1
from network_installation ni
where ni.network_id = n.network_id and
ni.installation_id = 1
);
If, somehow, you don't have a network table, you can replace the from clause with:
from (select distinct network_id from network_installation) n
EDIT:
You can do this in a single query with no subqueries, but a join is superfluous. Just use group by:
select ni.network_id
from network_installation ni
group by ni.network_id
having sum(ni.installation_id = 1) = 0;
The having clause counts the number of matches for the given installation for each network id. The = 0 is saying that there are none.
Another solution using OUTER JOIN:
SELECT t1.network_id, t1.installation_id, t2.network_id, t2.installation_id
FROM tab t1 LEFT JOIN tab t2
ON t1.network_id = t2.network_id AND t2.installation_id = 1
WHERE t2.network_id IS NULL
You can check at http://www.sqlfiddle.com/#!9/4798d/2
select *
from network_installations
where network_id in
(select network_id
from network_installations
where installation_id = 1
group by network_id )

How can I join these MYSQL tables?

I'm having 2 tables. Table A contains a list of people who booked for an event, table B has a list of people the booker from table A brings with him/her. Both tables have many colums with unique data that I need to do certain calculations on in PHP , and as of now I do so by doing queries on the tables with a recursive PHP function to resolve it. I want to simplify the PHP and reduce the amount of queries that come from this recursive function by doing better MYSQL queries but I'm kind of stuck.
Because the table has way to many columns I will give an Excerpt of table A instead:
booking_id | A_customer | A_insurance
1 | 134 | 4
Excerpt of table B:
id | booking_id | B_insurance
1 | 1 | 0
2 | 1 | 1
3 | 1 | 1
4 | 1 | 3
The booking_id in table A is unique and set to auto increment, the booking_id in table b can occur many times (depending on how many guests the client from table A brings with him). Lets say I want to know every selected insurance from customer 134 and his guests, then I want the output like this:
booking_id | insurance
1 | 4
1 | 0
1 | 1
1 | 1
1 | 3
I have tried a couple of joins and this is the closest I've came yet, unfortunately this fails to show the row from A and only shows the matching rows in B.
SELECT a.booking_id,a.A_customer,a.A_insurance,b.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
Can someone point me into the right direction ?
Please note: I have altered the table and column names for stackoverflow so it's easy for you guys to read, so it's possible that there is a typo that would break the query in it right now.
I think you need a union all for this:
select a.booking_id, a.insurance
from a
where a.a_customer = 134
union all
select b.booking_id, b.insurance
from a join
b
on a.booking_id = b.booking_id
where a.a_customer = 134;
The simplest way I can think of to achieve this is to use a UNION:
SELECT booking_id, A_insurance insurance
FROM A
WHERE booking_id = 134
UNION
SELECT booking_id, B_insurance insurance
FROM B
WHERE booking_id = 134
As my understanging of your isso is right, that should give you the result you need:
SELECT a.booking_id,a.insurance FROM a WHERE a.booking_id = 134
union
SELECT a.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134

SQL use of conditional AND on a join table to ensure at least two or multiple values are matched

I have a join table named languages_services that basically joins the table services and languages.
I need to find a service that is able to serve both ENGLISH (language_id=1) and ESPANOL (language_id=2).
table languages_services
------------------------
service_id | language_id
------------------------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
With the data provided above, I want to test for language_id=1 AND language_id=2 where the result would look like this
QUERY RESULT
------------
service_id
------------
1
Obviously it doesn't return the one with service_id=2 because it doesn't service Espanol.
Any tips on this is greatly appreciated!
SELECT
service_id
FROM
language_services
WHERE
language_id = 1
OR language_id = 2
GROUP BY
service_id
HAVING
COUNT(*) = 2
Or...
WHERE
lanaguage_id IN (1,2)
GROUP BY
service_id
HAVING
COUNT(*) = 2
If you're always looking at 2 languages you could do it with joins, but the aggregate version is easier to adapt to differing numbers of language_ids. (Add an OR, or add an item to the IN list, and change the COUNT(*) = 2 to COUNT(*) = 3, etc, etc).
Be aware, however, that this scales very poorly. And with this table structure there isn't much you can do about that.
EDIT Example using a join for 2 languages
SELECT
lang1.service_id
FROM
language_services AS lang1
INNER JOIN
language_services AS lang2
ON lang1.service_id = lang2.service_id
WHERE
lang1.language_id = 1
AND lang2.language_id = 2