I have the following SQL:
SELECT t.teilnehmer_id, t.familienname, t.vorname, t.ort, t.ortsteil, t.kontrolle_ertrag, t.kontrolle_1j, t.kontrolle_brache,
SUM(fe.nutzflaeche) AS nutzflaeche_ertrag, GROUP_CONCAT(fe.nutzflaeche) AS einzelfl_ertrag,
SUM(fp.nutzflaeche) AS nutzflaeche_pflanzj, GROUP_CONCAT(fp.nutzflaeche) AS einzelfl_pflanzj,
SUM(fb.nutzflaeche) AS nutzflaeche_brache, GROUP_CONCAT(fb.nutzflaeche) AS einzelfl_brache,
SUM(fn.nutzflaeche) AS nutzflaeche_nicht_aush, GROUP_CONCAT(fn.nutzflaeche) AS einzelfl_nicht_aush
FROM teilnehmer t
LEFT JOIN anrede a ON (t.anrede_id = a.anrede_id)
LEFT JOIN antragsform af ON (t.antragsform_id = af.antragsform_id)
LEFT JOIN bank b ON (t.bank_id = b.bank_id)
LEFT JOIN flurverzeichnis fe ON (t.teilnehmer_id = fe.teilnehmer_id AND fe.kulturbez = 'E')
LEFT JOIN flurverzeichnis fp ON (t.teilnehmer_id = fp.teilnehmer_id AND fp.kulturbez = 'P')
LEFT JOIN flurverzeichnis fb ON (t.teilnehmer_id = fb.teilnehmer_id AND fb.kulturbez = 'B')
LEFT JOIN flurverzeichnis fn ON (t.teilnehmer_id = fn.teilnehmer_id AND fn.kulturbez = 'N')
WHERE 1 = 1
GROUP BY t.teilnehmer_id
ORDER BY familienname, vorname
The sum doesn't reflect the correct areas if there is a match in more than one kulturbez. E.g. if I have 5 rows with kulturbez 'E' and 2 rows with kulturbez 'N', each 'E' row shows up twice and each 'N' row shows up 5 times. Any suggestions on how to redo the SQL to only sum each row with the matching kulturbez once?
Thanks,
Gunter
As indicated in my comment, unavoidable 1:N joins usually need subqueries to calculate aggregate values appropriately; but it looks like your need can be solved with conditional aggregation, like so:
SELECT t.teilnehmer_id, t.familienname, t.vorname, t.ort, t.ortsteil, t.kontrolle_ertrag, t.kontrolle_1j, t.kontrolle_brache
, SUM(CASE WHEN f.kulturbez = 'E' THEN f.nutzflaeche ELSE NULL END) AS nutzflaeche_ertrag
, GROUP_CONCAT(CASE WHEN f.kulturbez = 'E' THEN f.nutzflaeche ELSE NULL END) AS einzelfl_ertrag
, SUM(CASE WHEN f.kulturbez = 'P' THEN f.nutzflaeche ELSE NULL END) AS nutzflaeche_pflanzj
, GROUP_CONCAT(CASE WHEN f.kulturbez = 'P' THEN f.nutzflaeche ELSE NULL END) AS einzelfl_pflanzj
, SUM(CASE WHEN f.kulturbez = 'B' THEN f.nutzflaeche ELSE NULL END) AS nutzflaeche_brache
, GROUP_CONCAT(CASE WHEN f.kulturbez = 'B' THEN f.nutzflaeche ELSE NULL END) AS einzelfl_brache
, SUM(CASE WHEN f.kulturbez = 'N' THEN f.nutzflaeche ELSE NULL END) AS nutzflaeche_nicht_aush
, GROUP_CONCAT(CASE WHEN f.kulturbez = 'N' THEN f.nutzflaeche ELSE NULL END) AS einzelfl_nicht_aush
FROM teilnehmer t
LEFT JOIN anrede a ON (t.anrede_id = a.anrede_id)
LEFT JOIN antragsform af ON (t.antragsform_id = af.antragsform_id)
LEFT JOIN bank b ON (t.bank_id = b.bank_id)
LEFT JOIN flurverzeichnis f ON (t.teilnehmer_id = fe.teilnehmer_id)
WHERE 1 = 1
GROUP BY t.teilnehmer_id
ORDER BY familienname, vorname
Aggregate functions ignore NULL values for the most part. (Also, technically ELSE NULL is optional, as it is the assumed value if ELSE is not specified; but is good practice to make your intent clear.)
Related
SELECT (CASE WHEN DI.item_type = 'in_list' AND DI.item_method = 'item_category' AND DC.condition_method ='condition_time' THEN 'TimeDiscount' ELSE 0 END) AS TimeDiscount, (CASE WHEN DI.item_type = 'in_list' AND DI.item_method = 'item_category' AND DC.condition_method ='condition_date' THEN 'DateDiscount' ELSE 0 END) AS DateDiscount
FROM srampos_discount_item_list DIL JOIN srampos_discount_items DI ON DI.id = DIL.discount_item_id JOIN srampos_discounts D ON D.id = DI.discount_id JOIN srampos_discount_conditions DC ON D.id = DC.discount_id WHERE DIL.item_id =1
Thanks
sample records
TimeDiscount || DateDiscount
TimeDiscount || 0
0 || DateDiscount
i want to return to remove 0 and merge in one row
please help me Ths...
You could use a (fake) aggregation function eg: MAX() (and should be better use null instead of 0 )
SELECT max(CASE
WHEN DI.item_type = 'in_list'
AND DI.item_method = 'item_category'
AND DC.condition_method ='condition_time'
THEN 'TimeDiscount'
ELSE null END )AS TimeDiscount,
max(CASE
WHEN DI.item_type = 'in_list'
AND DI.item_method = 'item_category'
AND DC.condition_method ='condition_date'
THEN 'DateDiscount'
ELSE null END) AS DateDiscount
FROM srampos_discount_item_list DIL
JOIN srampos_discount_items DI ON DI.id = DIL.discount_item_id
JOIN srampos_discounts D ON D.id = DI.discount_id
JOIN srampos_discount_conditions DC ON D.id = DC.discount_id
WHERE DIL.item_id =1
everyone.
I am using grails 3.3.0.M2 framework with mysql as data-source the following sql query is working as expected
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) 'open',
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) 'in progress',
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) 'closed'
FROM
tickets t
INNER JOIN
users u ON t.user_id = u.id
INNER JOIN
user_coordinations uc ON uc.user_id = u.id
INNER JOIN
coordinations c ON c.id = uc.coordination_id
GROUP BY 1
I translated to HQL using implicit JOIN but I am getting the wrong results, here is the hql query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t, User u, UserCoordination uc, Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
In order to get the right results stack overflow users help me to understand that the query needs to use explicit JOINS, here the question: Group by a field that does not belongs to the consulted table
Right now I am trying with the following query:
SELECT
c.name,
SUM(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END),
SUM(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END)
FROM
Ticket t
INNER JOIN
User u
INNER JOIN
UserCoordination uc
INNER JOIN
Coordination c
WHERE
MONTH(t.dateCreated) = :month
GROUP BY 1
But i am getting a com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException with the caused message You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'inner join user_coordinations usercoordi2_ on inner join coordinations coordinat' at line 1
Thanks for your help and time
SELECT new map(
c.name as name,
(CASE
WHEN t.status = 'open' THEN 1
ELSE 0
END) as open,
(CASE
WHEN t.status = 'pending' THEN 1
ELSE 0
END) as pending,
(CASE
WHEN t.status = 'closed' THEN 1
ELSE 0
END) as closed,
SUM(open) as openSum,
SUM(pending) as pendingSum,
SUM(closed) as closedSum
)
FROM
Ticket t
left join t.user u left join u.userCoordination uc left join uc.coordination c
WHERE
MONTH(t.dateCreated) = :month
//GROUP BY 1
What you had had lots missing above is more like what you need, you need
select new map(i.item as item... if you compare the basics of this with what you had and what i tried to do you can see why you had errors.
unsure about your group by it should be group by something. Wasn't sure by inner join if you just meant a join if that was the case leave out all the left join since left join attempts to connect and get any null hasMany relations etc.
I have a problem how to combine the sql statements (inner join and union all. as a Newbie in SQL. Hopefully all members can help me to solve the problems.attached herewith the SQL. The leave_Trx and leave_History contain same values that need to be union. Thank you.
select m.name, t.startdt, t.enddt,t.noday,t.createdDT,
(case when t.approveST = 'Y' then 'Approved' when t.approveST = 'N' then 'Not Approved' else 'Pending' end) as appST
from leave_Trx t
inner join leave_MType m on m.typeID = t.trxID
inner join hr_personaldata b on b.pers_ID = #pers_ID
where year(t.startdt) = #yyear
and b.pers_ID = #pers_ID and b.pers_name LIKE '%'+#pers_name+'%'
and b.pers_compID LIKE ''+#compID+''
union all
select * from leave_History h
where year(h.startdt) = #yyear and h.status = 'A'
ORDER BY t.startdt
select t.pers_ID,t.startdt, t.enddt,t.noday,t.createdDT,
(case when t.approveST = 'Y' then 'Approved' when t.approveST = 'N' then 'Not Approved' else 'Pending' end) as appST
from leave_Trx t
inner join leave_MType m on m.typeID = t.pers_ID
inner join hr_personaldata l on l.pers_ID = #pers_ID
where year(t.startdt) = #yyear and t.status = 'A'
union all
select h.pers_ID, h.startdt, h.enddt,h.noday,h.createdDT,
(case when h.approveST = 'Y' then 'Approved' when h.approveST = 'N' then 'Not Approved' else 'Pending' end) as appST
from leave_History h
inner join leave_MType m on m.typeID = h.pers_ID
inner join hr_personaldata b on b.pers_ID = #pers_ID
where year(h.startdt) = #yyear and h.status = 'A'
I have a query (MySQL) which pulls data from 4 tables within the same database. What I would like to do is have the query run and have the results be either updated if there was a change and have new records be inserted into a separate table in another database.
SELECT a.Created,
a.id 'TicketID',
GROUP_CONCAT((CASE WHEN d.CustomField = 1 THEN d.Content ELSE NULL END)) `CompanyName`,
a.Subject,
c.Name Queue,
b.Name 'Owner',
a.`Status`,
a.LastUpdated,
GROUP_CONCAT((CASE WHEN d.CustomField = 4 THEN d.Content ELSE NULL END)) `Location`,
a.TimeWorked 'TimeWorked',
GROUP_CONCAT((CASE WHEN d.CustomField = 2 THEN d.Content ELSE NULL END)) `OverRide`,
a.Resolved
FROM rt.Tickets a
INNER JOIN rt.Users b
ON a.owner = b.id
INNER JOIN rt.Queues c
ON a.queue = c.id
INNER JOIN rt.ObjectCustomFieldValues d
ON a.id = d.ObjectID
GROUP BY a.id
The above query is pulls data from our ticketing system.
I was able to initally insert the data using the following:
INSERT INTO Support (Created, TicketID, CompanyName, Subject, Queue, Owner, Status, LastUpdated, Location, Timeworked, OverRide, Resolved)
SELECT a.Created,
a.id 'TicketID',
GROUP_CONCAT((CASE WHEN d.CustomField = 1 THEN d.Content ELSE NULL END)) `CompanyName`,
a.Subject,
c.Name Queue,
b.Name 'Owner',
a.`Status`,
a.LastUpdated,
GROUP_CONCAT((CASE WHEN d.CustomField = 4 THEN d.Content ELSE NULL END)) `Location`,
a.TimeWorked 'TimeWorked',
GROUP_CONCAT((CASE WHEN d.CustomField = 2 THEN d.Content ELSE NULL END)) `OverRide`,
a.Resolved
FROM rt.Tickets a
INNER JOIN rt.Users b
ON a.owner = b.id
INNER JOIN rt.Queues c
ON a.queue = c.id
INNER JOIN rt.ObjectCustomFieldValues d
ON a.id = d.ObjectID
GROUP BY a.id
However when trying to update the data that is already there or adding additional new data I get errors.
UPDATE Support
SELECT a.Created,
a.id 'TicketID',
GROUP_CONCAT((CASE WHEN d.CustomField = 1 THEN d.Content ELSE NULL END)) `CompanyName`,
a.Subject,
c.Name Queue,
b.Name 'Owner',
a.`Status`,
a.LastUpdated,
GROUP_CONCAT((CASE WHEN d.CustomField = 4 THEN d.Content ELSE NULL END)) `Location`,
a.TimeWorked 'TimeWorked',
GROUP_CONCAT((CASE WHEN d.CustomField = 2 THEN d.Content ELSE NULL END)) `OverRide`,
a.Resolved
FROM rt.Tickets a
INNER JOIN rt.Users b
ON a.owner = b.id
INNER JOIN rt.Queues c
ON a.queue = c.id
INNER JOIN rt.ObjectCustomFieldValues d
ON a.id = d.ObjectID
GROUP BY a.id
Thanks,
Given that the user you are using has proper permissions in both, you can do it this way:
INSERT INTO destination_database.table_name
(SELECT source_database.source_table.field_name
FROM source_database.source_table);
In your case your destination table must have 11 fields that you are selecting, with comparable data types.
It would be possible to define a view, rather than manually manage the 'derived table' yourself. Then the database can just reflect the changes in your source tables as they are made.
See: http://www.w3schools.com/sql/sql_view.asp
I have
users
------------------------
id | name | other_stuff.....
.
engagement
------------------------
user_id | type_code |
type_code is a varchar, but either A, B, C or NULL
[ EDIT for clarity: Users can have many engagements of each type code. SO I want to count how many they have of each. ]
I want to return ALL user rows, but with a count of A, B and C type engagements. E.g.
users_result
------------------------
user_id | user_name | other_stuff..... | count_A | count_B | count_C |
I've done quite a bit of searching, but found the following issues with other solutions:
The "other_stuff..." is actually grouped / concatenated results from a dozen other joins, so it's a bit of a monster already. So I need to be able to just add the additional fields to the pre-existing "SELECT ...... FROM users..." query.
The three additional required bits of data all come from the same engagement table, each with their own condition. I havent found anything to allow me to use the three conditions on the same related table.
Thanks
[edit]
I tried to simplify the question so people didn't have to look through loads of unnecessary stuff, but seems I might not have given enough info. Here is 'most' of the original query. I've taken out a lot of the selected fields as there are loads, but I've left most of the joins in so you can see basically what is actually going on.
SELECT
user.id,
user.first_name,
user.second_name,
GROUP_CONCAT(DISTINCT illness.id ORDER BY illness.id SEPARATOR ',' ) AS reason_for_treatment,
IF(ww_id=1000003, 1,'') as user_refused_program,
Group_CONCAT(DISTINCT physical_activity.name SEPARATOR ', ') AS programme_options,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM `user`
LEFT JOIN session AS session_induction ON (user.id = session_induction.user_id AND session_induction.session_type_id = 3)
LEFT JOIN stats AS stats_induction ON session_induction.id = stats_induction.session_id
LEFT JOIN session AS session_interim ON (user.id = session_interim.user_id AND session_interim.session_type_id = 4)
LEFT JOIN stats AS stats_interim ON session_interim.id = stats_interim.session_id
LEFT JOIN session AS session_final ON (user.id = session_final.user_id AND session_final.session_type_id = 5)
LEFT JOIN stats AS stats_final ON session_final.id = stats_final.session_id
LEFT JOIN user_has_illness ON user.ID = user_has_illness.user_id
LEFT JOIN illness ON user_has_illness.illness_id = illness.id
LEFT JOIN user_has_physical_activity ON user.ID = user_has_physical_activity.user_id
LEFT JOIN physical_activity ON user_has_physical_activity.physical_activity_id = physical_activity.id
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
WHERE (user.INDUCTION_DATE>='2010-06-09' AND user.INDUCTION_DATE<='2011-06-09' AND user.archive!='1' )
GROUP BY user.id, engagement_item.user_id
It's worth mentioning that it works fine - returns all users with all details required. Except for the count_A B and C cols.
[edit added slightly more simplified query below]
Stripped out the unrelated joins and selects.
SELECT
user.id,
user.first_name,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM `user`
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
GROUP BY user.id, engagement_item.user_id
SELECT e.user_id, u.name,
COUNT(CASE type_code WHEN 'A' THEN 1 ELSE NULL END) as count_A,
COUNT(CASE type_code WHEN 'B' THEN 1 ELSE NULL END) as count_B,
COUNT(CASE type_code WHEN 'C' THEN 1 ELSE NULL END) as count_C
FROM engagement e join users u on (e.user_id = u.id)
GROUP BY e.user_id, u.name
I would use COUNT instead of SUM just because that is what it is made for, counting things when not NULL.
SELECT
user.id,
user.first_name,
user.second_name,
GROUP_CONCAT(DISTINCT illness.id ORDER BY illness.id SEPARATOR ',' ) AS reason_for_treatment,
IF(ww_id=1000003, 1,'') as user_refused_program,
Group_CONCAT(DISTINCT physical_activity.name SEPARATOR ', ') AS programme_options,
ei.count_A, ei.count_B, ei.count_C
FROM `user`
LEFT JOIN ( SELECT user_id
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_A
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm12%' THEN 1 ELSE NULL END) as count_B
, COUNT(CASE WHEN engagement_item.type_code LIKE 'wm6%' THEN 1 ELSE NULL END) as count_C
FROM engagement_item
GROUP BY userid ) ei
LEFT JOIN session AS session_induction ON (user.id = session_induction.user_id AND session_induction.session_type_id = 3)
LEFT JOIN stats AS stats_induction ON session_induction.id = stats_induction.session_id
LEFT JOIN session AS session_interim ON (user.id = session_interim.user_id AND session_interim.session_type_id = 4)
LEFT JOIN stats AS stats_interim ON session_interim.id = stats_interim.session_id
LEFT JOIN session AS session_final ON (user.id = session_final.user_id AND session_final.session_type_id = 5)
LEFT JOIN stats AS stats_final ON session_final.id = stats_final.session_id
LEFT JOIN user_has_illness ON user.ID = user_has_illness.user_id
LEFT JOIN illness ON user_has_illness.illness_id = illness.id
LEFT JOIN user_has_physical_activity ON user.ID = user_has_physical_activity.user_id
LEFT JOIN physical_activity ON user_has_physical_activity.physical_activity_id = physical_activity.id
LEFT JOIN engagement_item ON user.ID = engagement_item.user_ID
WHERE (user.INDUCTION_DATE>='2010-06-09' AND user.INDUCTION_DATE<='2011-06-09' AND user.archive!='1' )
GROUP BY user.id, engagement_item.user_id, ei.count_A, ei.count_B, ei.count_C
Something like this perhaps?
select e.user_id, u.name,
sum(case e.type_code when 'A' then 1 else 0 end) as count_A,
sum(case e.type_code when 'B' then 1 else 0 end) as count_B,
sum(case e.type_code when 'C' then 1 else 0 end) as count_C
from engagement e join users u on (e.user_id = u.id)
group by e.user_id, u.name
The interesting part is the use of CASE inside the SUM to split the counting into three chunks.