Counting two tables with several conditions - mysql

I have two tables,
fenotipos
id DTHHRDX sex
GTEX-1117F 0 2
GTEX-ZE9C 2 1
K-562 1 2
atributos
SAMPID SMTS
K-562-SM-26GMQ Blood vessel
K-562-SM-2AXTU Blood_dry
GTEX-1117F-0003-SM-58Q7G Brain
GTEX-ZE9C-0006-SM-4WKG2 Brain
GTEX-ZE9C-0008-SM-4E3K6 Urine
GTEX-ZE9C-0011-R11a-SM-4WKGG Urine
I need to know how many women (sex=2) have DTHHRDX = 1 and have blood on SMTS.
For instance, the answer in this case would be 2

You could do:
select count(*) as cnt
from fenotipos f
where
sex = 2
and exists (
select 1
from atributos a
where a.sampid like concat(f.id, '%') and a.smts like 'Blood%'
)
This properly handles potential multiple matches in atributos
Alternatively, you could join:
select count(distinct f.id) as cnt
from fenotipos f
inner join atributos a on a.sampid like concat(f.id, '%')
where f.sex = 2 and a.smts like 'Blood%'
If there are no duplicates, then count(*) is more efficient than count(distinct f.id) in the second query.

Related

COUNT not returning expected values

Given the following relationship between my tables:
I need to show the name of films which only have two starring actors like 'Seconday'.
SELECT act.cod_film,
(SELECT COUNT(act.cod_film) FROM film, act WHERE act.starring like
'Seconday' and act.cod_film=film.cod_film) as namecounter
FROM act;
This always returns the films with the 'Seconday' actor, but the count is always same number. I need the number of 'Seconday' actors in each film.
Any help would be appreciated
This will locate films with 2 'Secondary' actors
SELECT act.cod_film
FROM act
GROUP BY act.cod_film
HAVING SUM(CASE WHEN act.starring like = 'Seconday' THEN 1 ELSE O END) = 2
which you can use in a subquery like this (or in many other possible ways)
SELECT *
FROM FILMS
WHERE cod_film IN (
SELECT act.cod_film
FROM act
GROUP BY act.cod_film
HAVING SUM(CASE WHEN act.starring like = 'Seconday' THEN 1 ELSE O END) = 2
)
or: Which you can use this way in a join
SELECT *
FROM FILMS
INNER JOIN (
SELECT act.cod_film, COUNT(*) NUM_OF
FROM act
GROUP BY act.cod_film
HAVING SUM(CASE WHEN act.starring like = 'Seconday' THEN 1 ELSE O END) = 2
) A ON FILMS.cod_film = A.cod_film
Notes:
like requires the use of a wildcard to be effective, don't substitute equals with like they are not the same things
you can adjust the = to >= as in sum(case...) >= 2 if you wanted a minimum of 2 secondary actors
The act table is mentioned 2 times, try remove the act from the select count()
Preposition 1
SELECT act.cod_film,
(SELECT COUNT(act.cod_film) FROM film WHERE act.starring like
'Seconday' and act.cod_film=film.cod_film) as namecounter
FROM act;
Preposition 2
SELECT act.cod_film, count(*)
FROM act JOIN film ON (act.act.cod_film = film.cod_film)
WHERE act.starring like 'Seconday'
GROUP BY act.cod_film

SQL "GROUP BY" and "INNER JOIN" Statements together

I have two tables of ANIMAL and NEED:
ANIMAL NEED
Name Species Birthday A_Species Type
Koala1 Phascolarctidae 02-10-2014 Phascolarctidae Veg.
Bear1 Ursinae 03-10-2016 Ursinae Veg.
Koala2 Phascolarctidae 04-09-2015 Ursinae Meet
Cattle1 Bovidae 20.03.2017 Ursinae Fish
Whale1 Cetacea 08.05.2010 Bovidae Veg.
Cetacea Fish
I would like to select the following table
Name Type
Koala1 Veg.
Koala2 Veg.
Cattle1 Veg.
Whale1 Fish
which is the list of name of animal and their food that needs only one type of food!
I have to combine two statement of
SELECT A_Species
FROM NEED GROUP BY A_Species
HAVING COUNT(A_Species)=1;
and
SELECT ANIMAL.NAME, NEED.Type
FROM ANIMAL
INNER JOIN NEED ON ANIMAL.Species = NEED.A_Species;
I tried
SELECT ANIMAL.NAME, NEED.Type
FROM ANIMAL
INNER JOIN NEED ON ANIMAL.Species = NEED.A_Species
WHERE EXISTS(SELECT A_Species
FROM NEED GROUP BY A_Species
HAVING COUNT(A_Species)=1);
which it is not working!
Can you help me how can I put them together?
One method uses aggregation:
SELECT a.NAME, MAX(n.Type)
FROM ANIMAL a INNER JOIN
NEED n
ON a.SPECIES = n.A_SPECIES
GROUP BY a.Name
HAVING COUNT(*) = 1;
Or an alternative uses NOT EXISTS:
SELECT a.NAME, n.Type
FROM ANIMAL a INNER JOIN
NEED n
ON a.SPECIES = n.A_SPECIES
WHERE NOT EXISTS (SELECT 1
FROM need n2
WHERE n2.A_SPECIES = n.A_SPECIES AND
n2.Type <> n.Type
);
In practice, this probably has better performance, particularly with an index on need(a_species, type).

SELECT COUNT(*) in a Left Join

So, I have a simple left join:
SELECT
a.SetNumber,
a.SetID,
COUNT(a.QuantityOwned) AS Pwnd,
b.ImageURL,
COUNT(a.Quantity) AS Cmplt
FROM a
LEFT JOIN b ON a.SetNumber = b.Number
GROUP BY a.SetID
That produces this:
SetNumber 11 21 13
SetID 1 2 1
Pwnd 45 33 50
Cmplt 50 36 50
ImgURL a.jpg b.jpg c.jpg
Which is fine, when I use the data, but I want a >> arrow in my pagination and to do that I would like to get the amount of rows, ie the desired result in this case is:
3
I know I can count rows with COUNT(*) in one table, but how do I do it in a left join?
I guess you need to do that
SELECT COUNT(1) FROM (SELECT a.SetNumber, a.SetID, COUNT(a.QuantityOwned) AS Pwnd ,b.ImageURL, COUNT(a.Quantity) AS Cmplt
FROM a
LEFT JOIN b ON a.SetNumber = b.Number
GROUP BY a.SetID) table1
The left join is'nt the problem here, it's the group by
But a lot of "Libraries" Allows to count the result count like
$result->count();
In my opinion if you use JAVA, php etc... you don't need to do another request

Conditionals and counts in SQL

I have a MySQL table
"ratings", with
an ID column
a column called like_dislike (holds either null, 0, or 1),
and a column called lesson_id (a foreign key from lessons).
the MySQL table, "lessons", with
an ID column
a teacher_id column
I need to select this information:
"SELECT r.like_dislike FROM ratings r INNER JOIN lessons l on l.lesson_id = r.lesson_id";
However, this actually part of a much larger SQL statement, and what I would like to do is:
Foreach lesson_id, if like_dislike == 0, SELECT count(like_dislike) as like
AND
Foreach lesson_id, if like_dislike == 1, SELECT count(like_dislike) as dislike
I do not know how to turn this pseudo code into SQL. I also need to do this in SQL, rather than in something like PHP, because it is part of a larger SQL statement whose conversion into properly formatted arrays is deeply troubling.
You should be able to accomplish this with grouping. For example:
SELECT r.lesson_id, COUNT(*) AS like
FROM ratings r
INNER JOIN lessons l ON l.lesson_id = r.lesson_id
WHERE r.like_dislike = 0
GROUP BY r.lesson_id;
The same for dislike, just change the WHERE clause to
WHERE r.like_dislike = 1
EDIT:
This can be combined into one query as requested, by adding another level of grouping:
SELECT r.lesson_id, r.like_dislike, COUNT(*) AS count
FROM ratings r
INNER JOIN lessons l ON l.lesson_id = r.lesson_id
GROUP BY r.lesson_id, r.like_dislike;
This will give you output, for example:
+-----------+--------------+-------+
| lesson_id | like_dislike | count |
+-----------+--------------+-------+
| 1 | 0 | 12 |
| 1 | 1 | 7 |
| 2 | 0 | 1 |
| 2 | 1 | 4 |
+-----------+--------------+-------+
so for lesson_id of 1, there are 12 likes, and 7 dislikes, etc...
EDIT 2:
To get one row for each lesson_id, you can modify the statement a little:
SELECT r.lesson_id,
CASE WHEN r.like_dislike = 0 THEN COUNT(*) END AS like,
CASE WHEN r.like_dislike = 1 THEN COUNT(*) END AS dislike
FROM ratings r
INNER JOIN lessons l ON l.lesson_id = r.lesson_id
GROUP BY r.lesson_id, r.like_dislike;
For that matter, you don't even need to join on the lessons table at all, unless you are somehow getting ratings that do not link to a lesson. If you want to include lessons that have no ratings, then you will have to change to an OUTER join:
SELECT l.lesson_id,
CASE WHEN r.like_dislike = 0 THEN COUNT(*) END AS like,
CASE WHEN r.like_dislike = 1 THEN COUNT(*) END AS dislike
FROM lessons l
LEFT JOIN ratings r ON r.lesson_id = l.lesson_id
GROUP BY l.lesson_id, r.like_dislike;
Maybe you can use a case statement, something like this:
SELECT r.lesson_id,
case when r.like_dislike == 0 then (count(*)) end as like,
case when r.like_dislike == 1 then (count(*)) end as dislike
FROM ratings r INNER JOIN lessons l ON l.lesson_id = r.lesson_id
GROUP BY r.lesson_id, r.like_dislike
I haven't tested it, but you can see the idea. Further, you must set a case to count 1's and another to count 0's because like_dislike can be null.
try this
SELECT if(r.like_dislike =0 ,count(like_dislike) as like , if( r.like_dislike =1 , count(like_dislike) as dislike, 'its null'))
FROM ratings r
INNER JOIN lessons l on l.lesson_id = r.lesson_id
if you are adding condition on yr datatable then code it like below:
Declare #Counter int
Set #Counter=(SELECT Count(Student_ID) as 'StudentCount' FROM tbCourseSemOne
where Student_ID=1 Having Count(Student_ID) < 6 and Count(Student_ID) > 0)
if(#Counter <6)
print'Sorry! You cannot add more than five subject data for a single stduent'
else
print'Insert Code'
hope it helps

Update Table by Join and Group by

A Company has many Reviews which has Rating Column itself.
CompID Ratig
12 3
13 3
17 4
22 4
23 5
24 3
28 3,2
This is what I need to be set to each company by id. Now Rating In Company Column is NULL.
I've written something like this:
UPDATE Companies c
JOIN Reviews r on c.CompanyID = r.CompanyID
SET c.Rating = AVG(r.rating)
group by r.CompanyID
This should do what you want using a simple nested query, in this case probably simpler than a JOIN.
UPDATE Companies
SET Rating =
(SELECT AVG(Rating)
FROM Ratings
WHERE Companies.CompanyId = Ratings.CompId)
Simple SQLfiddle demo here.
EDIT: If you really want to use a JOIN/UPDATE FROM, it'd look something like this;
UPDATE c
SET c.Rating = r.Rating
FROM Companies c
JOIN (SELECT AVG(Rating) Rating, CompID FROM Ratings GROUP BY CompId) r
ON c.CompanyId = r.CompId
At least to me, somewhat more complicated to read, and afaik it only works on SQL Server, but here's the SQLfiddle for that too :)
UPDATE ComisionesxColaboradorxLineaPrescripciones
SET CANTIDAD_PRODUCTOS_CORE_CUMPLE = CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones ComisionesxColaboradorxLineaPrescripciones
INNER JOIN
(SELECT TAB_L.COD_COLAB AS COD_COLAB,TAB_L.TIPO_COLABORADOR AS TIPO_COLABORADOR, COUNT(TAB_P.COD_SEG) AS CANTIDAD
FROM #ComisionesxColaboradorxLineaPrescripciones TAB_L
INNER JOIN #ComisionesxColaboradorxLineaxProductoPrescripciones TAB_P
ON TAB_L.COD_COLAB=TAB_P.COD_COLAB AND
TAB_L.TIPO_COLABORADOR=TAB_P.TIPO_COLABORADOR
GROUP BY TAB_L.COD_COLAB,TAB_L.TIPO_COLABORADOR
) AGRUPADO
ON ComisionesxColaboradorxLineaPrescripciones.COD_COLAB = AGRUPADO.COD_COLAB AND
ComisionesxColaboradorxLineaPrescripciones.TIPO_COLABORADOR = AGRUPADO.TIPO_COLABORADOR