An explanation with SQL query - mysql

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;

Related

Count field and group by regarding another field on same table MySQL

I am trying to find count of field by another field in same table on MySQL.My Table Like This:
Id DrgId CodeType IsPrincipal Code
182250051 48261836 I 1 T151
182250055 48261836 I 2 U739
182250059 48261836 I 3 Y929
182250061 48261836 I 4 W444
182250062 48261836 A 2 3006104
So I want to find used helper codes for T151 which is IsPrincipal equals 1.
Output should like this:
Code Helper_I_Count Helper_A_Count
T151 3 1
So I tried Like this:
SELECT t.`Code`,COUNT(v1.`Code`) AS EkTaniSay,COUNT(v2.`Code`) AS IslemSay
FROM TIGPatientCode t,
(
SELECT DRGPatientId,`Code`
FROM TIGPatientCode
WHERE IsPrincipal<>'1' AND CodeType='I'
) v1,
(
SELECT DRGPatientId,`Code`
FROM TIGPatientCode
WHERE IsPrincipal<>'1' AND CodeType='A'
) v2
WHERE t.IsPrincipal='1' AND t.DRGPatientId=v1.DRGPatientId AND t.DRGPatientId=v2.DRGPatientId
GROUP BY t.`Code`
But it wont get actual count.
How can I Do this?
Thanks
SELECT t2.Code,
SUM(t1.CodeType = 'I') AS EkTaniSay,
SUM(t1.CodeType = 'A') AS IslemSay
FROM TIGPatientCode AS t1
RIGHT JOIN TIGPatientCode AS t2 ON t1.DrgPatientId = t2.DrgPatientId
WHERE t1.isPrincipal != 1 AND t2.isPrincipal = 1
GROUP BY t1.DrgPatientId;
The first part of the query is based on multiple query same table but in different columns mysql. Then I join this with the table again to get the code for the principal row.
The problem with your query is that joining the two subqueries creates a cross-product of all the rows, which causes the counts to be multiplied. Also, if there's any group that doesn't have one of the codes, that subquery will return no rows, so the join will be empty for that code. You could fix the first problem by doing the counts in the subqueries rather than the main query. The second problem can be fixed by using LEFT JOIN. So the fixed version of your query would look like:
SELECT t.Code, v1.EkTaniSay, v2.IslemSay
FROM TIGPatientCode t
LEFT JOIN (
SELECT DRGPatientId, COUNT(*) AS EkTaniSay
FROM TIGPatientCode
WHERE IsPrincipal<>'1' AND CodeType='I'
GROUP BY DRGPatientId
) AS v2 ON t.DRGPatientId = v2.DRGPatientId
LEFT JOIN (
SELECT DRGPatientId, COUNT(*) AS IslemSay
FROM TIGPatientCode
WHERE IsPrincipal<>'1' AND CodeType='A'
GROUP BY DRGPatientId
) AS v1 ON t.DRGPatientId = v1.DRGPatientId
WHERE t.IsPrincipal = 1
DEMO

Select field based on value in same record

I want to SELECT a field based on a ID value.
Products
PRODUCT_ID Name
19 Chair
20 Table
Product_fields
ID PRODUCT_ID TYPE DESCRIPTION
1 19 C White
2 19 S Modern
3 20 C Black
4 20 S Classic
I need a result like:
Product Type_C Type_S
Chair White Modern
Table Black Classic
I am able to produce this using two LEFT JOINs on the product_fields table but this slows down the query too much. Is there a better way?
Slows down the query how much? What is acceptable?
If you really don't want to use joins (you must have one join), then use views or nested queries. But I don't think they will be any faster, though you can give it a try.
See views at sqlfiddle
select p.PRODUCT_ID, p.Name, f.CDescription, f.SDescription
from Products p
join(
SELECT PRODUCT_ID, Max( CDescription ) as CDescription,
Max( SDescription ) as SDescription
FROM(
select PRODUCT_ID,
case Type when 'C' then Description end as CDescription,
case Type when 'S' then Description end as SDescription
from Fields
) x
group by PRODUCT_ID
) f
on f.PRODUCT_ID = p.PRODUCT_ID;
The complete statement is:
SELECT
NL.product_name,
PRD.product_sku AS product_sku,
CF.virtuemart_product_id AS virtuemart_product_id,
GROUP_CONCAT(distinct CFA.customsforall_value_name
ORDER BY CFA.customsforall_value_name ASC
separator ' | ' ) AS Name_exp_3,
ROUND((((prices.product_price * CALC.calc_value) / 100) + prices.product_price),
2) AS Prijs,
VMCF_L.custom_value AS latijn,
VMCF_T.custom_value AS THT
VMCF_B.custom_value AS Batch
from j25_virtuemart_products AS PRD
LEFT join j25_virtuemart_product_custom_plg_customsforall AS CF ON CF.virtuemart_product_id = PRD.virtuemart_product_id
join j25_virtuemart_product_prices AS prices ON PRD.virtuemart_product_id = prices.virtuemart_product_id
join j25_virtuemart_calcs AS CALC ON prices.product_tax_id = CALC.virtuemart_calc_id
join j25_virtuemart_products_nl_nl AS NL ON NL.virtuemart_product_id = PRD.virtuemart_product_id
LEFT join j25_virtuemart_product_customfields AS VMCF ON VMCF.virtuemart_product_id = PRD.virtuemart_product_id
LEFT join j25_virtuemart_custom_plg_customsforall_values AS CFA ON CFA.customsforall_value_id = CF.customsforall_value_id
LEFT JOIN j25_virtuemart_product_customfields AS VMCF_L ON VMCF.virtuemart_product_id = VMCF_L.virtuemart_product_id AND VMCF_L.virtuemart_custom_id = 16
LEFT JOIN j25_virtuemart_product_customfields AS VMCF_T ON VMCF.virtuemart_product_id = VMCF_T.virtuemart_product_id AND VMCF_T.virtuemart_custom_id = 3
LEFT JOIN j25_virtuemart_product_customfields AS VMCF_B ON VMCF.virtuemart_product_id = VMCF_B.virtuemart_product_id AND VMCF_B.virtuemart_custom_id = 18
WHERE
PRD.product_sku like '02.%'
group by PRD.virtuemart_product_id
order by NL.product_name;
Where the three SELECT results named 'Latijn', 'THT', and 'Batch' are the ones which I compared earlier as the black/white and classic/modern values.
Hope this makes any sense.
As you can see this involves a Virtuemart installation, so I cannot fiddle about to much with the schema.
When I exclude the bottom 3 JOINS and there related FIELDS, the query takes approx 0,5 seconds. With the JOINS and FIELDS included, the query takes almost 19 seconds.
I have created a view from this complete query which I query from my labeling application.
Thanks everyone! With your input I created:
select
NL.product_nameASproduct_name,
PRD.product_skuASproduct_sku,
CF.virtuemart_product_idASvirtuemart_product_id,
group_concat(distinctCFA.customsforall_value_name
order byCFA.customsforall_value_nameASC
separator ' | ') ASName_exp_3,
round((((prices.product_price*CALC.calc_value) / 100) +prices.product_price),
2) ASPrijs,
f.LatijnASLatijn,
f.THTASTHT,
f.BatchASBatch
from
(((((((j25_virtuemart_productsPRD
left joinj25_virtuemart_product_custom_plg_customsforallCFON ((CF.virtuemart_product_id=PRD.virtuemart_product_id)))
joinj25_virtuemart_product_pricespricesON ((PRD.virtuemart_product_id=prices.virtuemart_product_id)))
joinj25_virtuemart_calcsCALCON ((prices.product_tax_id=CALC.virtuemart_calc_id)))
joinj25_virtuemart_products_nl_nlNLON ((NL.virtuemart_product_id=PRD.virtuemart_product_id)))
left joinj25_virtuemart_product_customfieldsVMCFON ((VMCF.virtuemart_product_id=PRD.virtuemart_product_id)))
left joinj25_virtuemart_custom_plg_customsforall_valuesCFAON ((CFA.customsforall_value_id=CF.customsforall_value_id)))
left joinvw_batch_Latijn_THT_groupedfON ((f.virtuemart_product_id=PRD.virtuemart_product_id)))
where
(PRD.product_skulike '02.%')
group byPRD.virtuemart_product_id
order byNL.product_name``
Which takes 1.4 seconds to execute, a whole lot faster then the 19 seconds I started with.

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

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;

SQL Left Join Multiple Tables and count values conditionally in each table

I am having some trouble putting together a SQL statement properly because I don't have much experience SQL, especially aggregate functions. Safe to say I don't really know what I'm doing outside of the basic SQL structure. I can do regular joins, but not complex ones.
I have some tables: 'Survey', 'Questions', 'Session', 'ParentSurvey', and 'ParentSurveyQuestion'. Structurally, a survey can have questions, it can have users that started the survey (a session), and it can have a parent survey whose questions get imported into the current survey.
What I want to do is get information for a each survey in the Survey table; total questions it has, how many sessions have been started (conditionally, ones that have not finished), and the number of questions in the parents survey. The three joined tables can but do not have to contain any values, and if they don't then 0 should be returned by COUNT. The common field in three of the tables is a variation of 'survey_id'
Here is my SQL so far, I put the table structure below it.
SELECT
`kp_survey_id`,
COALESCE( q.cnt, 0 ) AS questionsAmount,
COALESCE( s.cnt, 0 ) AS sessionsAmount
COALESCE( p.cnt, 0 ) AS parentQAmount,
FROM `Survey`
LEFT JOIN <-- I'd like the count of questions for this survey
( SELECT COUNT(*) AS cnt
FROM Questions
GROUP BY kf_survey_id ) q
ON Survey.kp_survey_id = Questions.kf_survey_id
LEFT JOIN
( SELECT COUNT(*) AS cnt <-- I'd like the count of started sessions for this survey
FROM Session
WHERE session_status = 'started' <-- should this be Session.session_status?
GROUP BY kf_survey_id ) s
ON Survey.kp_survey_id = Session.kf_survey_id
LEFT JOIN
( SELECT COUNT(*) AS cnt <-- I'd like the count of questions in the parent survey with this survey id
FROM ParentSurvey
GROUP BY kp_parent_survey_id ) p
ON Survey.kf_parent_survey_id = ParentSurveyQuestion.kf_parent_survey_id
'kp' prefix means primary key, while 'kf' prefix means foreign key
Structure:
Survey: 'kp_survey_id' | 'kf_parent_survey_id'
Question: 'kp_question_id' | 'kf_survey_id'
Session: 'kp_session_id' | 'kf_survey_id' | 'session_status'
ParentSurvey: 'kp_parent_survey_id' | 'survey_name'
ParentSurveyQuestion: 'kp_parent_question_id' | 'kf_parent_survey_id'
There are also other columns in each table like 'name' or 'account_id', but i don't think they matter in this case
I'd like to know if I'm doing this correctly or if I'm missing something. I'm repurposing some code I found here on stackoverflow and modifying it to meet my needs, as I haven't seen conditional aggregation for more than three tables on this site.
My expected output is something like:
kp_survey_id | questionsAmount | sessionsAmount | parentQAmount
1 | 3 | 0 | 3
2 | 0 | 5 | 3
I think you were pretty close -- just need to fix your joins and include the survey id in the subqueries to use in those joins:
SELECT
`kp_survey_id`,
COALESCE( q.cnt, 0 ) AS questionsAmount,
COALESCE( s.cnt, 0 ) AS sessionsAmount
COALESCE( p.cnt, 0 ) AS parentQAmount,
FROM `Survey`
LEFT JOIN
( SELECT COUNT(*) cnt, kf_survey_id AS cnt
FROM Questions
GROUP BY kf_survey_id ) q
ON Survey.kp_survey_id = q.kf_survey_id
LEFT JOIN
( SELECT COUNT(*) cnt, kf_survey_id
FROM Session
WHERE session_status = 'started'
GROUP BY kf_survey_id ) s
ON Survey.kp_survey_id = s.kf_survey_id
LEFT JOIN
( SELECT COUNT(*) cnt, kp_parent_survey_id
FROM ParentSurvey
GROUP BY kp_parent_survey_id ) p
ON Survey.kf_parent_survey_id = p.kp_parent_survey_id
One thing you need to do is correct your joins. When you are joining to a subquery, you need to use the alias of the subquery. In your case you are using the alias of the table being used in the subquery.
Another thing you need to change is to include the field you wish to use in your JOIN in the subquery.
Make these changes and try running. Do you get an error or the desired results?
SELECT
`kp_survey_id`,
COALESCE( q.cnt, 0 ) AS questionsAmount,
COALESCE( s.cnt, 0 ) AS sessionsAmount
COALESCE( p.cnt, 0 ) AS parentQAmount,
FROM `Survey`
LEFT JOIN <-- I'd like the count of questions for this survey
( SELECT kf_survey_id, COUNT(*) AS cnt
FROM Questions
GROUP BY kf_survey_id ) q
ON Survey.kp_survey_id = q.kf_survey_id
LEFT JOIN
( SELECT kf_survey_id, COUNT(*) AS cnt <-- I'd like the count of started sessions for this survey
FROM Session
WHERE session_status = 'started' <-- should this be Session.session_status?
GROUP BY kf_survey_id ) s
ON Survey.kp_survey_id = s.kf_survey_id
LEFT JOIN
( SELECT kp_parent_survey_id, COUNT(*) AS cnt <-- I'd like the count of questions in the parent survey with this survey id
FROM ParentSurvey
GROUP BY kp_parent_survey_id ) p
ON Survey.kf_parent_survey_id = p.kf_parent_survey_id

How to left join or inner join a table itself

I have this data in a table, for instance,
id name parent parent_id
1 add self 100
2 manage null 100
3 add 10 200
4 manage null 200
5 add 20 300
6 manage null 300
How can I left join or inner join this table itself so I get this result below?
id name parent
2 manage self
4 manage 10
6 manage 20
As you can I that I just want to query the row with the keyword of 'manage' but I want the column parent's data in add's row as the as in manage's row in the result.
Is it possible?
EDIT:
the simplified version of my actual table - system,
system_id parent_id type function_name name main_parent make_accessible sort
31 30 left main Main NULL 0 1
32 31 left page_main_add Add self 0 1
33 31 left page_main_manage Manage NULL 0 2
my actual query and it is quite messy already...
SELECT
a.system_id,
a.main_parent,
b.name,
b.make_accessible,
b.sort
FROM system AS a
INNER JOIN -- self --
(
SELECT system_id, name, make_accessible, sort
FROM system AS s2
LEFT JOIN -- search --
(
SELECT system_id AS parent_id
FROM system AS s1
WHERE s1.function_name = 'page'
) AS s1
ON s1.parent_id = s2.parent_id
WHERE s2.parent_id = s1.parent_id
AND s2.system_id != s1.parent_id
ORDER BY s2.sort ASC
) b
ON b.system_id = a.parent_id
WHERE a.function_name LIKE '%manage%'
ORDER BY b.sort ASC
result I get currently,
system_id main_parent name make_accessible sort
33 NULL Main 0 1
but I am after this,
system_id main_parent name make_accessible sort
33 self Main 0 1
You just need to reference the table twice:
select t1.id, t1.name, t2.id, t2.name
from TableA t1
inner join TableA t2
on t1.parent_id = t2.Id
Replace inner with left join if you want to see roots in the list.
UPDATE:
I misread your question. It seems to me that you always have two rows, manage one and add one. To get to "Add" from manage:
select system.*, (select parent
from system s2
where s2.parent_id = system.parent_id
and s2.name = 'add')
AS parent
from system
where name = 'manage'
Or, you might split the table into two derived tables and join them by parent_id:
select *
from system
inner join
(
select * from system where name = 'add'
) s2
on system.parent_id = s2.parent_id
where system.name = 'manage'
This will allow you to use all the columns from s2.
Your data does not abide to a child-parent hierarchical structure. For example, your column parent holds the value 10, which is not the value of any id, so a child-parent association is not possible.
In other words, there's nothing that relates the record 2,manage,null to the record 1,add,self, or the record 4,manage,null to 3,add,10, as you intend to do in your query.
To represent hierarchical data, you usually need a table that has a foreign key referencing it's own primary key. So your column parent must reference the column id, then you can express a child-parent relationship between manage and add. Currently, that's not possible.
UPDATED: Joining by parent_id, try:
select m.id, m.name, a.parent
from myTable m
join myTable a on m.parent_id = a.parent_id and a.name = 'add'
where m.name = 'manage'
Change the inner join to a left join if there may not be a corresponding add row.