MySQL Subquery Syntax + ZF2 Syntax - mysql

I have a football database with 10k+ rows. My goal is to select one player by his id and get all other players which are in the same league or club or have the same nationality.
My query so far is the following:
SELECT *
FROM `characteristics`
WHERE `nation` = (SELECT `nation`
FROM `characteristics`
WHERE `id` = "1")
OR `club` = (SELECT `club`
FROM `characteristics`
WHERE `id` = "1")
OR `league` = (SELECT `league`
FROM `characteristics`
WHERE `id` = "1")
I think the query doesn't work as I expected, because it will return 1434 rows. For example: Nation = Argentina, League = BBVA, Club = FC Barcelona will return together something about 1500+ rows.
Maybe you guys can help me with this subquery.
Another problem is the subquery syntax in ZF2. I found something here on stackoverflow, but I can't figure the syntax out where to put something.
EDIT: example of db data
id firstname lastname age height nation club league
1 Lionel Messi 28 170 cm Argentina FC Barcelona Liga BBVA

I can't answer regarding ZF2 as I am not working with this.
For your SQL question, I think you are looking for this :
SELECT C1.`id` as playerid,
C1.firstname as playerfirstname,
C1.lastname as playerlastname,
C2.*
FROM `characteristics` C1
INNER JOIN `characteristics` C2
ON ( C1.`nation` = C2.`nation` OR
C1.`club` = C2.`club` OR
C1.`league` = C2.`league` )
WHERE C1.`id` = "1"
The idea is to retrieve the player from characteristics (alias C1) and then to JOIN the table characteristics again (alias C2) on the columns you specified.

Related

It's correct this Exercise Query SQL?

I have this DB
aeroporto(1) <----> (n)volo(n) <----> (1)aereo
AEROPORTO: (pK)id_ap, città, naz, num_pist
VOLO: (pk)id_volo, data, (fk)id_part, oraPart, (fk)id_arr, oraArr, (fk)tipoAereo
AEREO: (pk)id_aereo, qta_merci, num_pass, cod_aereo
/ * French cities from which more than twenty direct flights to Italy leave * /
select a.citta
from volo as v, aereoporto as a, aereoporto as b
where a.id_ap = v.id_part and b.id_ap = v.id_arr and
a.nazione != b.nazione and a.nazione = 'francia' and count(b.citta = 'italia') > 20 ;
It's correct?
Sorry for my poor english.
Return the city name of all cities leaving 'francia' and arriving in 'italia' having a count of flights > 20.
SELECT a.citta
FROM volo as v
INNER JOIN aereoporto as a
on a.id_ap = v.id_part
INNER JOIN aereoporto as b
on b.id_ap = v.id_arr
WHERE a.nazione = 'francia'
and b.nazione = 'italia'
GROUP BY a.citta
HAVING count(v.id_volo) > 20 ;
GROUP BY allows us to group like cities together from 'francia' and the having clause lets us count the flights and ensure we only show cities having more than 20 flights.
However, this does assume that a citta is not duplicated per naz. For example: if the the same named city existed in different regions within francia; then we would have a problem. So if there were a Paris Brittany and a Paris Île-de-France and both had airports going to itally; then the a.citta for Paris would be the count of both Paris cities; which may not be the desired results. Without a unique identifier which describes a.citta on which we group this problem could persist. So maybe we need to group by a.citta and a.id_ap and display both in the select so the user knows "Which airport' we're talking about. Alternatively; I believe each airport is assigned a code defining it specifically; if that were tracked as part of the airport information; we could group on it and avoid the a.id_ap. City alone isn't enough to make a record unique.
Example:
SELECT a.citta, a.id_ap
FROM volo as v
INNER JOIN aereoporto as a
on a.id_ap = v.id_part
INNER JOIN aereoporto as b
on b.id_ap = v.id_arr
WHERE a.nazione = 'francia'
and b.nazione = 'italia'
GROUP BY a.citta, a.id_ap
HAVING count(v.id_volo) > 20 ;
I don't like using cross joins in the from clause which is the , notation in the from does. This style of join is from the 1980's and should be given up in favor of the explicit syntax of inner, left, right, full outer and cross join.
My reasoning for this is the FROM clause should define the tables being used and how they relate in most cases. The where clause should be used to limit the data being returned; mixing the two comes at a cost of confusion and more difficult maintenance long term. The only exception to this rule is outer join which may need to limit the data as part of the join to maintain the integrity of the outer join.
To address comment:
Something like this may work: if the total count of flights from a cities airport matches the count of arrivals coming from italia and destinations to italia then all flights are internal/domestic; otherwise do not show that airport. So the having clause like the where, acts as the filter to exclude cities with flights arriving from or departing to other countries. This approach is a bit more ambiguous on what it's doing but from a performance standpoint it should operate better than an in, not exists, or subqueries would given proper indexes on fields.
SELECT a.citta, a.id_ap
FROM volo as v
INNER JOIN aereoporto as a
on a.id_ap = v.id_part
INNER JOIN aereoporto as b
on b.id_ap = v.id_arr
GROUP BY a.citta, a.id_ap
HAVING count(v.id_volo) = sum(case when a.nazione = 'italia' then 1 else 0 end as ItalianArrivals)
and count(v.id_volo) = sum(case when b.nazione = 'italia' then 1 else 0 end as ItalianDepartures);
Given the ambiguity of the above, maintenance may be a bit harder for the next person so by using an explicit not exists once for arrivals and once for departures you can achieve the same results; but I do not believe it would be as optimal in performance... However, it too would achieve the proper results. I prefer not exists over not in when dealing with a data set that can grow in size to over 50 values. Since the query relates to a data set that looks like it would continue to grow, not exists seems like the 2nd best choice over the not in; with the having I believe being better performance on the larger datasets.
I tried hardly to figure out your example and what is the exact output you are trying to retrieve and I think the below shall help you.
SELECT a.citta
FROM aereoporto as a, volo as v
WHERE a.id_ap = v.id_part AND a.nazione = 'francia'
GROUP BY a.citta having count(*) > 20 ;
Mockup Data
aereoporto
id_ap citta nazione
1 rome italia
2 milan italia
3 paris francia
4 bordeaux francia
volo
id_volo data id_part oraPart id_arr oraArr tipoAereo
1 NULL 3 NULL 1 NULL NULL
2 NULL 3 NULL 1 NULL NULL
3 NULL 3 NULL 2 NULL NULL
4 NULL 4 NULL 2 NULL NULL
5 NULL 4 NULL 1 NULL NULL

SQL: SELECT where 2 columns from different tables are the same

I need to work with a database that contains info about (former) Presidents. I need to check if there a presidents that have the same hobbies AND are married in the same year.
So a president can have multiple hobbies in pres_hob table. And the marriage year is in the pres_mar table, in the mar_year column.
I've tried to INNER JOIN the tables in SQLite where the hobby and mar_year are equal, except for the pres_name. This way the JOIN doesnt work ofcourse, which makes sense. Im kinda new to this..
Any help is appreciated
Here's one option with multiple joins:
select p1.pres_name, p2.pres_name, ph.hobby
from pres_mar p1
join pres_mar p2 on p1.pres_name != p2.pres_name and p1.mar_year = p2.mar_year
join pres_hob ph on p1.pres_name = ph.pres_name
join pres_hob ph2 on p2.pres_name = ph2.pres_name and ph.hobby = ph2.hobby
And depending on your expected results, another option using exists:
select pm.pres_name, ph.hobby
from pres_mar pm
join pres_hob ph on pm.pres_name = ph.pres_name
where exists (
select 1
from pres_mar pm2
join pres_hob ph2 on pm2.pres_name = ph2.pres_name
where pm.pres_name != pm2.pres_name and
ph.hobby = ph2.hobby
)
That sounds like a terrible database schema, I'm assuming its for learning purposes, anyway, you could do something like
SELECT
h.name,
h.hobby,
m.year
FROM
pres_hob h,
pres_mar m
WHERE
h.hobby = 'tennis'
AND
m.year = 2016
This would return 1 record for every president with a marriage year of 2016 , and a hobby of Tennis.

SQL Query Questions for a text (Nested NOT EXISTS)

I have been struggling with this for a while now so maybe someone can shed some insight.
We have a practice query that comes from a TVShow database that for this problem has 4 tables.
This is the query: Sponsors that sponsor all tv shows by ABC
What I have tried so far is this but it doesn't seem to be working:
SELECT DISTINCT RSPONSOR.SPONSOR_NAME
FROM RSPONSOR
WHERE NOT EXISTS (
SELECT *
FROM RTVSHOW
WHERE NOT EXISTS (
SELECT *
FROM RSPONSORBY
WHERE RSPONSOR.SPONSOR_NAME = RSPONSORBY.SPONSOR_NAME
AND RSPONSORBY.SHOW_NUM = RTVSHOW.SHOW_NUM
AND RTVSHOW.NETWORK_ID = 'ABC'
)
);
Would love any help! Thanks in advance.
Here are the tables for reference
--RTVSHOW--
SHOW_NUM NUMBER
SHOW_NAME VARCHAR2(20 BYTE)
START_MONTH NUMBER
START_YEAR NUMBER
END_MONTH NUMBER
END_YEAR NUMBER
NETWORK_ID VARCHAR2(20 BYTE)
DISTR_NAME VARCHAR2(20 BYTE)
--RSPONSOR--
SPONSOR_NAME
PARENT_NAME
--RSPONSORBY--
SHOW_NUM
SPONSOR_NAME
--RNETWORK--
NETWORK_ID
NETWORK_HQ
PARENT_NAME
select rSponsor.sponsor_name, rSponsor.parent_name
from rSponsor
join rSponsorBy
on rSponsor.sponsor_name = rSponsorBy.sponsor_name
join rTVShow
on rSponsorBy.show_num = rTVShow.show_num
join rNetwork
on rTVShow.network_id = rNetwork.network_id
where rNetwork.network_id = 'ABC'
group by rSponsor.sponsor_name, rSponsor.parent_name
having count(distinct rTVShow.show_num) = --ABC shows sponsored by this sponsor
(
select count(distinct rTVShow.show_num) --ABC shows
from rTVShow
join rNetwork
on rTVShow.network_id = rNetwork.network_id
where
rNetwork.network_id = 'ABC'
);

Check if there are multiple values in a column

I have the following sql:
SELECT DISTINCT cp_pessoa.id, cp_pessoa.nome
FROM cp_pessoa
LEFT JOIN cp_habilidade_freelancer ON (cp_habilidade_freelancer.id_freelancer = cp_pessoa.id)
LEFT JOIN cp_habilidade ON (cp_habilidade.id = cp_habilidade_freelancer.id_habilidade)
WHERE cp_habilidade.id = 71 OR cp_habilidade.id = 695
LIMIT 0, 10
I only want people (cp_pessoa) who have all the skills (71, 695).
It may seem simple, but I'm struggling.
Examples:
If I use OR the following people with the following skills (1,2,71) are returned (people without the ability 695)
If I use AND the following people with the following skills (71, 695) are not returned
Is this homework? If so, the idea should suffice: You are looking for persons where the count of the associtated skills 71 and 695 is 2.
In case this is no homework, but a real task, then tell me so and I'll give you a complete SQL statement :-)
EDIT: The straight-forward way is to ask if both skills exist for a person:
select id, nome
from cp_pessoa p
where exists
(
select *
from cp_habilidade_freelancer hf
where hf.id_freelancer = p.id
and hf.id_habilidade = 71
)
and exists
(
select *
from cp_habilidade_freelancer hf
where hf.id_freelancer = p.id
and hf.id_habilidade = 695
);
The other way with querying cp_habilidade_freelancer just once:
select id, nome
from cp_pessoa p
where id in
(
select id_freelancer
from cp_habilidade_freelancer hf
where id_habilidade in (71, 695)
group by id_freelancer
having count(distinct id_habilidade) = 2
);
You could change count(distinct id_habilidade) to count(*) in case it is guaranteed that there are no duplicate skills for an id_freelancer in cp_habilidade_freelancer.

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