SQL Select outter Join and Group By and IFNULL ( COUNT ) HELP =x - mysql

I have this database and i was wondering to create a great select but is too hard for me I guess I tried so many ways and I get really close, but i cant go longer.
Database
Table -> Candidato | IdCandidato(int) | idNome(varchar)
Table -> Voto | idVoto(int) | Candidato_idCandidato(int) | DiaVotacao(date)
i am creating a web voting system and need i greate select to complet my graphics to show the total voting for each day for each candidate.
Candidato = candidate | voto = vote | diaVotacao = voting day (english translation)
I need i response like this:
|VotingDay---------|-----Candidate1----------|-----Candidate2------|--Candidate3
|2014-05-14-------|---13(total votes)---------|------------4------------|-----------10|
|2014-05-15-------|---18(total votes)---------|------------0------------|------------8|
and so far i got this:
|VotingDay---------|-----TOTAL Votes----------|-----Name------|
|2014-05-14-------|---13(total votes)---------|-Candidate1
|2014-05-14-------|---18(total votes)---------|-Candidate2
|2014-05-15-------|---10(total votes)---------|-Candidate1
|2014-05-15-------|----8(total votes)---------|-Candidate2
I used the following code:
SELECT voto.DiaVotacao, IFNULL(COUNT(voto.Candidato_idCandidato),0) as Votos, candidato.Nome
FROM candidato LEFT OUTER JOIN voto ON voto.Candidato_idCandidato=candidato.idCandidato
GROUP BY voto.DiaVotacao, voto.Candidato_idCandidato
Note that i want the count of the votes for each candidate for everey day and if there is no votes apear the number 0 to indicate no votes
did u guys understand?

You need to generate the full list of candidates and days and then do the left outer join. You can get the list of days from the votos table.
Note that when you use count(<column>), it will return 0 if all the values are NULL. There is no need for ifull() or coalesce():
SELECT d.DiaVotacao, COUNT(v.Candidato_idCandidato) as Votos, c.Nome
FROM candidato c cross join
(SELECT DISTINCT v.DiaVotacao FROM voto v
) d LEFT OUTER JOIN
voto v
ON v.Candidato_idCandidato = c.idCandidato and
v.DiaVotacao = d.DiaVotacao
GROUP BY d.DiaVotacao, v.Candidato_idCandidato;

Related

Select from SQL database information with newest revisions

I coding web app for my client and have issue with selecting from database raports with newest revisions.
SELECT
raports.*,
r1.*,
users.*,
(SELECT COUNT(*) FROM changes WHERE changes.changes_raports_id = raports.raports_id) as changes,
(SELECT changes.changes_date FROM changes WHERE changes.changes_raports_id = raports.raports_id ORDER BY changes.changes_date DESC LIMIT 1) as last_change,
(SUM(injuries.injuries_min_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as min,
(SUM(injuries.injuries_max_procent) / COUNT(injuries_to_raports.injuries_to_raports_id)) as max
FROM raports
LEFT JOIN users
ON users.users_id = raports.raports_users_id
LEFT JOIN changes
ON changes.changes_raports_id = raports.raports_id
LEFT JOIN raports_to_changes r1
ON r1.raports_to_changes_raports_id = raports.raports_id
LEFT JOIN injuries_to_raports
ON injuries_to_raports.injuries_to_raports_raports_id = r1.raports_to_changes_raports_id
LEFT JOIN injuries
ON injuries_to_raports.injuries_to_raports_injuries_id = injuries.injuries_id
WHERE r1.raports_to_changes_changes_id = (SELECT max(raports_to_changes_changes_id) FROM raports_to_changes r2 WHERE r2.raports_to_changes_raports_id = r1.raports_to_changes_raports_id)
GROUP BY raports.raports_id ORDER BY raports.raports_id ASC;
In columns max and min i have not correct average from injuries. When i checked it and count all injuries i had 36 when true number is 2 but i have 18 revisions. So is logic that i have looped COUNT with all revisions but i want only the newest
I try changing WHERE statements and more LEFT JOINs but nothing helped.
Could someone fixed that code?
Thank you in advanced
Based on the clues revealed by your queries, the data model may look like this:
The select list shows that you need:
users information of a reports_id
aggregated injuries_min_procent and injuries_max_procent at raports_id level. (see cte_raport_injuries)
number of changes of a raports_id (see cte_raport_changes)
the last change_date of a raports_id (see cte_raport_changes)
I'm not sure about the need for raports_of_changes based on information revealed in the question, so I'm going to ignore it for now.
with cte_raport_injuries as (
select r.raports_id,
sum(i.injuries_min_procent) / count(*) as injuries_min_procent,
sum(i.injuries_max_procent) / count(*) as injuries_max_procent
from raports r
join injuries_to_raports ir
on r.raports_id = ir.injuries_to_raports_raports_id
join injuries i
on ir.injuries_to_raports_injuries_id = i.injuries_id
group by r.raports_id),
cte_raport_changes as (
select r.raports_id,
count(c.changes_id) as changes,
max(c.changes_date) as last_change
from raports r
join changes c
on r.raports_id = c.changes_raports_id
group by r.raports_id)
select u.users_id,
r.raports_id,
ri.injuries_min_procent,
ri.injuries_max_procent,
rc.changes,
rc.last_change
from raports r
join users u
on r.raports_users_id = u.users_id
join cte_raport_injuries ri
on r.raports_id = ri.raports_id
join cte_raport_changes rc
on r.raports_id = rc.raports_id;
The result looks like this:
users_id|raports_id|injuries_min_procent|injuries_max_procent|changes|last_change|
--------+----------+--------------------+--------------------+-------+-----------+
1| 11| 15.0000| 25.0000| 2| 2022-12-02|
So my question for you is what's in reports_to_changes that you need and what's its relationship between others? For further involvement from the community, you may want to share the following information in text format:
DDLs of each tables (primary key, foreign key, column names & data types)
Some representable sample data and basic business rules
Expected output

SQL Distinct based on different colum

I have problem to distinct values on column based on other column. The case study is:
Table: List
well | wbore | op|
------------------
wella|wbore_a|op_a|
wella|wbore_a|op_b|
wella|wbore_a|op_b|
wella|wbore_b|op_c|
wella|wbore_b|op_c|
wellb|wbore_g|op_t|
wellb|wbore_g|op_t|
wellb|wbore_h|op_k|
So, I want the output to be appear in different field/column like:
well | total_wbore | total_op
----------------------------
wella | 2 | 3
---------------------------
wellb | 2 | 2
the real study case come from different table but to simplify it I just assume this case happened in 1 table.
The sql query that I tried:
SELECT well.well_name, wellbore.wellbore_name, operation.operation_name, COUNT(*)
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name,wellbore.wellbore_name
HAVING COUNT(*) > 1
But this query is to calculate the duplicate row which not meet the requirement. Anyone can help?
you need to use count distinct
SELECT
count(distinct wellbore.wellbore_name) as total_wbore
count(distinct operation.operation_name) as total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
Final query:
SELECT
well.well_name,
COUNT(DISTINCT wellbore.wellbore_name) AS total_wbore,
COUNT(DISTINCT operation.operation_name) AS total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name

Multiple joins on same table

I'm trying to achieve a query which seems simple but I can't make it work correctly. Here's my database tables structures:
members
-> id
-> last_name
-> first_name
activities
-> id
registrations
-> id
-> member_id
tandems
-> id
-> activitie_id
-> registration_member_one
-> registration_member_two
Here's what i want to achieve:
Mutliple members can register to an activity. Then, i group the registrations by tandems. I want a view with all the tandems listed and there's my problem. When I try a query, it gives me multiple rows, duplicated many times.
Below, an example of the table I want to have:
tandems.id | activities.id | registration_member_one.members.last_name | registration_member_two.members.last_name
1 | 3 | John Doe | Jane Doe
Here's the query I'm working on:
SELECT
tandems.*,
memberOne.id, memberOne.last_name, memberOne.first_name,
memberTwo.id, memberTwo.last_name, memberTwo.first_name,
memberOne_registration.member_id as memberOne,
memberTwo_registration.member_id as memberTwo
FROM tandems
JOIN registrations as memberOne_registration
ON memberOne_registration.member_id = tandems.registration_member_one
JOIN members as memberOne ON memberOne.id = memberOne_registration.member_id
JOIN registrations as memberTwo_registration
ON memberTwo_registration.member_id = tandems.registration_member_two
JOIN members as memberTwo ON memberTwo.id = memberTwo_registration.member_id
WHERE activitie_id = 3;
Any help appreciated!
The error is caused by joining wrong column (member_id) of registrations table with tandems table, instead column registrations.id should be used.
SELECT
tandems.*,
memberOne.id, memberOne.last_name, memberOne.first_name,
memberTwo.id, memberTwo.last_name, memberTwo.first_name,
memberOne_registration.id as memberOne,
memberTwo_registration.id as memberTwo
FROM tandems
JOIN registrations as memberOne_registration ON memberOne_registration.id = tandems.registration_member_one
JOIN members as memberOne ON memberOne.id = memberOne_registration.member_id
JOIN registrations as memberTwo_registration ON memberTwo_registration.id = tandems.registration_member_two
JOIN members as memberTwo ON memberTwo.id = memberTwo_registration.member_id
WHERE activitie_id = 3;
Although other query is virtually the same, I hate working with unnecessarily long alias names so worked with "r1" and "r2" for the two instances of the registration table, and "m1" and "m2" for the members joining context.
SELECT
t.id,
t.activitie_id,
m1.last_name LastName1,
m1.first_name FirstName1,
m2.last_name LastName2,
m2.first_name FirstName2
FROM
tandems t
LEFT join registrations r1
ON t.registration_member_one = r1.id
LEFT JOIN members m1
ON r1.member_id = m1.id
LEFT join registrations r2
ON t.registration_member_two = m2.id
LEFT JOIN members m2
ON r2.member_id = m2.id
WHERE
t.activitie_id = 3;
To help you on this and in the future... Although mentally done, I try to mentally draw out how do I get the pieces together from the first table downstream. This can be seen too by the visual indentation almost like a tree view extension from T to R1 to M1, then R2 to M2 is a different branch. I also prefer to list the left table/alias.column = right table/alias.column in the join condition. How does T get to R1, then how does R1 get to M1.
In this, I used LEFT JOIN to each respective registration and member -- just-in-case only one person registered and a second may be pending. Not sure how your registration is actually structured.

Selecting IDs from a MIN query that includes join

sorry about the title, very bad at titles!
I have these relevant tables:
Times
+--------+----------+-------------+------+---------+
| TimeID | PlayerID | MapCourseID | Mode | RunTime |
+--------+----------+-------------+------+---------+
Checkpoints
+--------------+--------+------------+---------+
| CheckpointID | TimeID | Checkpoint | RunTime |
+--------------+--------+------------+---------+
Maps
+-------+------+
| MapID | Name |
+-------+------+
MapCourses
+-----------+-------+--------+
| MapCourse | MapID | Course |
+-----------+-------+--------+
RunTime stores their "time" as an int
I have a query that selects the fastest times for a specific map MapID on all courses and all modes
SELECT MIN(Times.RunTime), MapCourses.Course, Times.Mode
FROM Times
INNER JOIN MapCourses ON MapCourses.MapCourseID=Times.MapCourseID
INNER JOIN Players ON Players.PlayerID=Times.PlayerID
WHERE Players.Cheater=0 AND MapCourses.MapID=%d
GROUP BY MapCourses.Course, Times.Mode;
Which works fine, but now I want to make another query that selects the checkpoints of the fastest times, since checkpoints are associated with a TimeID
I've tried doing something like this
SELECT * FROM Checkpoints
INNER JOIN (
SELECT
MIN(Times.RunTime),
MapCourses.Course,
Times.Mode,
MapCourses.MapID,
Players.SteamID32
FROM
Times
INNER JOIN MapCourses ON MapCourses.MapCourseID = Times.MapCourseID
INNER JOIN Players ON Players.PlayerID = Times.PlayerID
WHERE
Players.Cheater = 0
AND MapCourses.MapID = %d
GROUP BY
MapCourses.Course,
Times.Mode
) AS wrs ON Checkpoints.TimeID = wrs.TimeID
Also tried something like this:
SELECT
Checkpoints.RunTime,
Checkpoints.Checkpoint,
MapCourses.Course,
Times.Mode,
Times.TimeID,
Players.Alias
FROM
Checkpoints
INNER JOIN Times ON Times.TimeID = Checkpoints.TimeID
INNER JOIN MapCourses ON MapCourses.MapCourseID = Times.MapCourseID
INNER JOIN Players ON Players.PlayerID = Times.PlayerID
WHERE
Players.Cheater = 0
AND MapCourses.MapID = %d
AND Times.RunTime = (
SELECT
MIN(Times.RunTime)
FROM
Times
WHERE
Times.MapCourseID = MapCourses.MapCourseID
AND Mode = Times.Mode
)
Neither seem to really work, any help would be great, thanks!
Basically, if i'm working on map id 50, I already have a query that gets the fastest time on map id 50 for all modes & courses, the query i'm trying to build is a query that gets the checkpoints of the fastest times for every course and mode on map id 50
We could do something like this:
SELECT c.checkpointid
, c.timeid
, c.checkpoint
, c.runtime
, ...
FROM ( SELECT t.mapcourseid
, t.mode
, MIN(r.runtime) AS min_runtime
FROM Times r
JOIN Players p
ON p.playerid = r.playerid
AND p.cheater = 0
JOIN MapCourses s
ON s.mapcourseid = t.mapcourse_id
AND s.mapid = ?
GROUP
BY t.mapcourseid
, t.mode
) q
JOIN Times t
ON t.runtime = q.min_runtime
AND t.mapcourseid = q.mapcourseid
JOIN Checkpoints c
ON c.timeid = t.timeid
The trick here is using a query as an inline view. The result returned from the query inside the parens gets returned as a resultset, which is then used like a table by the outer query. MySQL calls it a "derived table".
In the outer SELECT list, we can include references to columns from q and t as well as c.
Note: If there are two or more rows from t that match the minimumn runtime (returned by q), the query will return all of the matching rows.
The specification is a bit unclear. The query in this answer satisfies one particular interpretation.
If I'm following this correctly, you want the shortest Checkpoints.TimeID for each Checkpoint in a similar format to the above?
SELECT MIN(Checkpoints.TimeID), MapCourses.Course, Checkpoints.Checkpoint, Times.Mode
FROM Checkpoints
INNER JOIN Times ON Checkpoints.TimeID=Times.TimeID
INNER JOIN MapCourses ON MapCourses.MapCourseID=Times.MapCourseID
INNER JOIN Players ON Players.PlayerID=Times.PlayerID
WHERE Players.Cheater=0 AND MapCourses.MapID=%d
GROUP BY MapCourses.Course, Checkpoints.Checkpoint, Times.Mode;
Obviously not having access to your Database I can't test this, but, seems to be what you're asking?
[edit]
Ahh, so you want to keep the min times, but would like to add checkpoints into the returned values:
SELECT MIN(Times.RunTime), MapCourses.Course, Checkpoints.Checkpoint, Times.Mode
FROM Times
INNER JOIN MapCourses ON MapCourses.MapCourseID=Times.MapCourseID
INNER JOIN Players ON Players.PlayerID=Times.PlayerID
INNER JOIN Checkpoints ON Checkpoints.TimeID=Times.TimeID
WHERE Players.Cheater=0 AND MapCourses.MapID=%d
GROUP BY MapCourses.Course, Checkpoints.Checkpoint, Times.Mode;
So this should return your fastest time, the map, checkpoints and then mode.

An explanation with SQL query

I trying to get some data for my JavaFX Application from a couple of tables in database with MySQl.
Here's the query:
select veturattable.id, veturattable.vetura,veturattable.modeli,veturattable.ngjyra,
veturattable.targa, renttable.pagesa, hargjimettable.shuma
from veturattable
left join hargjimettable
on hargjimettable.veturaid= veturattable.id
left join renttable
on renttable.veturaid = veturattable.id ;
Here are datas from rentable
And here are datas from hargjimettable
So what I need is to show me this one:
veturaid | pagesa | shuma
1 | 150 | 91
10 | 110 | 40
You actually need to do two subqueries pre-aggregating the sum amounts per respective ID. Then join each individually back to the main. If you don't, you are getting a Cartesian product. For every record in the hargjimettable table for a given ID, it is joined to the renttable for each amount there. So, if you have 2 records in first table and 3 records in the second, you are getting a multiple of 6.
By pre-querying each grouping by the one ID key respectively, you will only have at most, one record for each possible summation. So grab that record if it exists. The left-join prevents some IDs from not showing up. Using coalesce() prevents nulls from showing.
select
v.id,
v.vetura,
v.modeli,
v.ngjyra,
v.targa,
COALESCE( RSum.SumPagesa, 0 ) as AllPagesa,
COALESCE( HSum.SumShuma, 0 ) as AllShuma
from
veturattable v
left join
( select
h.veturaid,
SUM( h.shuma ) as SumShuma
from
hargjimettable h
group by
h.veturaid ) HSum
ON v.id = HSum.veturaid
left join
( select
r.veturaid,
SUM( r.pagesa ) as SumPagesa
from
renttable r
group by
r.veturaid ) RSum
ON v.id = RSum.veturaid
You actually want the MAX() and SUM() along the GROUP BY like
select max(veturattable.id) as id, max(veturattable.vetura) as vetura,
max(veturattable.modeli) as modeli,
max(veturattable.ngjyra) as ngjyra,
max(veturattable.targa) as targa,
max(renttable.pagesa) as pagesa,
sum(hargjimettable.shuma) as shuma
from veturattable
left join hargjimettable
on hargjimettable.veturaid= veturattable.id
left join renttable
on renttable.veturaid = veturattable.id
group by veturattable.id;