SQL Select if else - mysql

I need some help.. I need to output the value of DisplayName if the value of fullname return a null or empty as FullName.
something like
if(u.first_name && u.last_name are not empty)
output CONCAT(u.first_name,' ',u.last_name)
else
output max(case when t.field_id = 1 then t.value else '' end)
but how? also my query took 3.45 seconds :(..
SELECT * FROM(
SELECT
t.user_id,
##this code
max(case when t.field_id = 1 then t.value else '' end) DisplayName,
CONCAT(u.first_name,' ',u.last_name) FullName,
max(case when t.field_id = 270 then t.value else '' end) Gender,
max(case when t.field_id = 274 then t.value else '' end) Birthday,
max(case when t.field_id = 274 then FLOOR(DATEDIFF(CURRENT_DATE, STR_TO_DATE(t.value,'%m/%d/%Y'))/365) else '' end) Age,
max(case when t.field_id = 275 then t.value else '' end) Phone,
max(case when t.field_id = 286 then t.value else '' end) Email,
max(case when t.field_id = 71 then t.value else '' end) Occupation,
max(case when t.field_id = 73 then t.value else '' end) CurrentCountry,
max(case when t.field_id = 24 then t.value else '' end) Region,
max(case when t.field_id = 355 then t.value else '' end) Province,
max(case when t.field_id = 354 then t.value else '' end) City
FROM wp_bp_xprofile_data t
LEFT JOIN (
SELECT
user_id id,
max(case when meta_key = 'first_name' then meta_value end) first_name,
max(case when meta_key = 'last_name' then meta_value end) last_name
from wp_usermeta
GRoup by user_id
)as u
ON u.id = t.user_id
GROUP BY user_id
)temp
WHERE 1 = 1
##Some Condition to be added
LIMIT 0 , 30

I would change to a multiple join to same table repeatedly to get each field on its own criteria
as a possibility of performance. Start the profile data one for say the field_id = 1 as the basis,
then join all the rest on that same key, then no grouping by or max/case when on every tested row.
IF some fields may NOT exists, just have as LEFT-JOIN to the re-used table with alternate alias.
I would ensure you have a compound/covering index on your profile table with the following key
( user_id, field_id, value )
Then do the following query. The interesting thing here, is it basically opens the same table for each "component" part of the user_ID and gets them all lined up, but runs the query based only on a single instance of records associated with field_id = 1 in the where clause. All the other instances are in their respective aliases joined ON clause. So now, I just run through the records for field_id = 1, and if found on the other tables, grabs the value, otherwise blank (via coalesce). Similarly joined to the user meta-data table to get the first/last name parts.
if this works for you, I would be interested in knowing the performance one-way or the other. The benefit is that it doesn't have to query EVERYONE up front (the inner-most query) to then run the main query of all records, apply the group by, then stop at your 30 limit clause. It just gets up to the first 30 where field_id = 1 and its done. Now, if the population of "field_id = 1" is a low populated field, and you want to swap with another, so be it, you know your data better than us.
SELECT
DN.User_ID,
case when fn.user_id is null and ln.user_id is null then DN.value
when fn.user_id is null then ln.meta_value
when ln.user_id is null then fn.meta_value
else concat( fn.meta_value, ' ', ln.meta_value ) end as FinalName,
DN.Value DisplayName,
CONCAT( COALESCE( fn.meta_value, '' ),' ',COALESCE( ln.meta_value, '' )) FullName,
COALESCE( G.Value, '' ) Gender,
COALESCE( BD.Value, '' ) Birthday,
COALESCE( FLOOR( DATEDIFF( CURRENT_DATE, STR_TO_DATE( BD.value,'%m/%d/%Y'))/365), '' ) Age,
COALESCE( P.Value, '' ) Phone,
COALESCE( E.Value, '' ) Email,
COALESCE( O.Value, '' ) Occupation,
COALESCE( CC.Value, '' ) CurrentCountry,
COALESCE( R.Value, '' ) Region,
COALESCE( PR.Value, '' ) Province,
COALESCE( C.Value, '' ) City
from
wp_bp_xprofile_data DN
LEFT JOIN wp_bp_xprofile_data G
ON DN.User_ID = G.User_ID AND G.field_id = 270
LEFT JOIN wp_bp_xprofile_data BD
ON DN.User_ID = BD.User_ID AND BD.field_id = 274
LEFT JOIN wp_bp_xprofile_data P
ON DN.User_ID = P.User_ID AND P.field_id = 275
LEFT JOIN wp_bp_xprofile_data E
ON DN.User_ID = E.User_ID AND E.field_id = 286
LEFT JOIN wp_bp_xprofile_data O
ON DN.User_ID = O.User_ID AND O.field_id = 71
LEFT JOIN wp_bp_xprofile_data CC
ON DN.User_ID = CC.User_ID AND CC.field_id = 73
LEFT JOIN wp_bp_xprofile_data R
ON DN.User_ID = R.User_ID AND R.field_id = 24
LEFT JOIN wp_bp_xprofile_data PR
ON DN.User_ID = PR.User_ID AND PR.field_id = 355
LEFT JOIN wp_bp_xprofile_data C
ON DN.User_ID = C.User_ID AND C.field_id = 354
LEFT JOIN wp_usermeta FN
ON DN.User_ID = FN.User_ID AND FN.meta_key = 'first_name'
LEFT JOIN wp_usermeta LN
ON DN.User_ID = LN.User_ID AND LN.meta_key = 'last_name'
where
DN.field_id = 1
AND O.Value like '%Programmer%'
LIMIT
0, 30
I modified to add a FINAL Name by use of a case/when.
if both the alias FN/LN (first name / last name) are BOTH null, then get the DN (display name) value. Otherwise we have AT LEAST ONE or BOTH parts of the first/last name field. If the first name was null, just return the last name. If the last name was null, return the first name, otherwise BOTH first and last names were available, and return the concatinated version of the name.
As for applying extra WHERE clauses. As soon as you add a "required" criteria to the where clause against any of the left-join aliases, it will in-effect turn them into INNER JOINs and only include those that HAVE that component AND that component has the value you want... So, per your comment I would just add...
where
DN.field_id = 1
AND BD.User_ID IS NOT NULL
AND STR_TO_DATE( BD.value,'%m/%d/%Y') BETWEEN '2009-01-01' and '2012-01-01'
You could use your datediff for age and do that between 1 and 2, but just a preference to pick a date range of interest..
For your additional comment about Programmer filtering, the way you had it was trying to test ALL the joined aliases looking for programmer, but at the same time, all of them required because you wanted them all as NOT NULL. If you want a field required, but no other specific criteria, such as ALWAYS must have email address, then just change
LEFT JOIN wp_bp_xprofile_data E
to
JOIN wp_bp_xprofile_data E
if you want to make sure the field is considered only if it has a value other than space (such as your last/first name)
LEFT JOIN wp_usermeta FN
ON DN.User_ID = FN.User_ID
AND FN.meta_key = 'first_name'
AND LENGTH( TRIM( COALESCE( FN.meta_Value, '' ))) > 0
This will make sure the record is only considered when it actually has a non-empty string value.
Back to your consideration of "%Programmer%'... why would you ever expect a city, Province, region, etc to have a value of programmer. You should only require the Occupation instance to have the value. Also, because you had an OR, it was doing ALL the rows. You would need to have wrapped the conditions something like
where
DN.field_id = 1
AND ( O.Value like '%Programmer%'
OR E.Value like '%#gmail.com'
OR C.Value like 'Some City' )
Notice I wrapped my ADDITIONAL criteria OR components. This way it still only starts with the Field_ID = 1 entries, but based on the JOIN adds the extra criteria, and in this case, DN.field_id = 1 always, but ANY ONE (or more) of the OR conditions must also be true... The Occupation alias has a value like programmer, email alias has a value of gmail, the city alias like 'Some City'.
Hopefully this clarifies how to implement... Also, make note, that using any LIKE qualifier that has '%' leading the string needs to compare through the whole string and will slow the query down some, but since the join is based on the user ID and the field_ID value, that should still keep it fast (relatively).

Try this:
SELECT if( trim(CONCAT(first_name,' ', lastName))='',
DisplayName,
CONCAT(first_name,' ', lastName) ) as Name
...rest of the fieds on TA subquery
FROM (
(SELECT
t.user_id,
max(case when t.field_id = 1 then t.value else '' end) DisplayName,
max(case when t.field_id = 270 then t.value else '' end) Gender,
max(case when t.field_id = 274 then t.value else '' end) Birthday,
max(case when t.field_id = 274
then FLOOR( DATEDIFF( CURRENT_DATE,
STR_TO_DATE( t.value, '%m/%d/%Y')) / 365)
else '' end) Age,
max(case when t.field_id = 275 then t.value else '' end) Phone,
max(case when t.field_id = 286 then t.value else '' end) Email,
max(case when t.field_id = 71 then t.value else '' end) Occupation,
max(case when t.field_id = 73 then t.value else '' end) CurrentCountry,
max(case when t.field_id = 24 then t.value else '' end) Region,
max(case when t.field_id = 355 then t.value else '' end) Province,
max(case when t.field_id = 354 then t.value else '' end) City
FROM wp_bp_xprofile_data t
GROUP BY user_id
) TA
LEFT JOIN
( SELECT user_id id,
max(case when meta_key = 'first_name'
then meta_value end) first_name,
max(case when meta_key = 'last_name'
then meta_value end) last_name
from wp_usermeta
GRoup by user_id ) as U on (ta.user_id = U.id)
)temp
WHERE 1 = 1
##Some Condition to be added
LIMIT 0 , 30

Related

Grouping different column into one row

How to make one row in different rows and column
SELECT
internal_id, store_id, user_id, shift_info,
DATE(log_datetime) dates,
(case when log_action = '0' then TIME(log_datetime) end) as time_in,
(case when log_action = '0' then CONCAT(log_lat, ",", log_lng) end) as loc_in,
(case when log_action = '1' then TIME(log_datetime) end) as time_out,
(case when log_action = '1' then CONCAT(log_lat, ",", log_lng) end) as loc_out
FROM
attendance_store_user
WHERE
user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"
i want result like this :
You could try using a join of the same table filter for null time_out and time_in
select a.dates, a.store_id, a,time_in, b.time_out
FROM attendance_store_user a
INNER JOIN attendance_store_user b on a.dates = b.dates
and a.user_id = b.user_id
and a.time_out is null
and b.time_in is null
WHERE a.user_id = "A4CBD64F-D21C-5612-CCF5-497892B62E76"

MySQL - Slow Query when adding multiple derived tables - Optimization

For my query, the two derived tables at the bottom are causing a crazy slow up for this query. The query, as is, takes about 45-55 seconds to execute.. NOW, when i remove just one of those derived tables (it does not matter which one) the query goes down to 0.1 - 0.3 seconds. My questions; Is there an issue with having multiple derived tables? Is there a better way to execute this? My indexes all seem to be correct, I will also include the explain from this query.
select t.name as team, u.name as "REP NAME",
count(distinct activity.id) as "TOTAL VISITS",
count(distinct activity.account_id) as "UNIQUE VISITS",
count(distinct placement.id) as "COMMITMENTS ADDED",
CASE WHEN
count(distinct activity.account_id) = 0 THEN (count(distinct
placement.id) / 1)
else (cast(count(distinct placement.id) as decimal(10,2)) /
cast(count(distinct activity.account_id) as decimal(10,2)))
end as "UNIQUE VISIT TO COMMITMENT %",
case when o.mode='basic' then count(distinct placement.id) else
count(distinct(case when placement.commitmentstatus='fullfilled'
then placement.id else 0 end))
end as "COMMITMENTS FULFILLED",
case when o.mode='basic' then 1 else
(CASE WHEN
count(distinct placement.id) = 0 THEN (count(distinct(case when
placement.commitmentstatus='fullfilled' then placement.id else 0
end)) / 1)
else (cast(count(distinct(case when
placement.commitmentstatus='fullfilled' then placement.id else 0
end)) as decimal(10,2)) / cast(count(distinct placement.id) as
decimal(10,2)))
end) end as "COMMITMENT TO FULFILLMENT %"
from lpmysqldb.users u
left join lpmysqldb.teams t on t.team_id=u.team_id
left join lpmysqldb.organizations o on o.id=t.org_id
left join (select * from lpmysqldb.activity where
org_id='555b918ae4b07b6ac5050852' and completed_at>='2018-05-01' and
completed_at<='2018-06-01' and tag='visit' and accountname is not
null and (status='active' or status='true' or status='1')) as
activity on activity.user_id=u.id
left join (select * from lpmysqldb.placements where
orgid='555b918ae4b07b6ac5050852' and placementdate>='2018-05-01' and
placementdate<='2018-06-01' and (status IN ('1','active','true') or
status is null)) as placement on placement.userid=u.id
where u.org_id='555b918ae4b07b6ac5050852'
and (u.status='active' or u.status='true' or u.status='1')
and istestuser!='1'
group by u.org_id, t.name, u.id, u.name, o.mode
order by count(distinct activity.id) desc
Thank you for assistance!
I have edited below with changing the two bottom joins from joining on subqueries to joining on the table directly. Still yielding the same result.
This is a SLIGHTLY restructured query of your same. Might be simplified as the last two subqueries are all pre-aggregated for your respective counts and count distincts so you can use those column names directly instead of showing all the count( distinct ) embedded throughout the query.
I also tried to simplify the division by multiplying a given count by 1.00 to force decimal-based precision as result.
select
t.name as team,
u.name as "REP NAME",
Activity.DistIdCnt as "TOTAL VISITS",
Activity.UniqAccountCnt as "UNIQUE VISITS",
Placement.DistIdCnt as "COMMITMENTS ADDED",
Placement.DistIdCnt /
CASE WHEN Activity.UniqAccountCnt = 0
THEN 1.00
ELSE Activity.UniqAccountCnt * 1.00
end as "UNIQUE VISIT TO COMMITMENT %",
case when o.mode = 'basic'
then Placement.DistIdCnt
else Placement.DistFulfillCnt
end as "COMMITMENTS FULFILLED",
case when o.mode = 'basic'
then 1
else ( Placement.DistFulfillCnt /
CASE when Placement.DistIdCnt = 0
then 1.00
ELSE Placement.DistIdCnt * 1.00
END TRANSACTION )
END as "COMMITMENT TO FULFILLMENT %"
from
lpmysqldb.users u
left join lpmysqldb.teams t
on u.team_id = t.team_id
left join lpmysqldb.organizations o
on t.org_id = o.id
left join
( select
user_id,
count(*) as AllRecs,
count( distinct id ) DistIdCnt,
count( distinct account_id) as UniqAccountCnt
from
lpmysqldb.activity
where
org_id = '555b918ae4b07b6ac5050852'
and completed_at>='2018-05-01'
and completed_at<='2018-06-01'
and tag='visit'
and accountname is not null
and status IN ( '1', 'active', 'true')
group by
user_id ) activity
on u.id = activity.user_id
left join
( select
userid,
count(*) AllRecs,
count(distinct id) as DistIdCnt,
count(distinct( case when commitmentstatus = 'fullfilled'
then id
else 0 end )) DistFulfillCnt
from
lpmysqldb.placements
where
orgid = '555b918ae4b07b6ac5050852'
and placementdate >= '2018-05-01'
and placementdate <= '2018-06-01'
and ( status is null OR status IN ('1','active','true')
group by
userid ) as placement
on u.id = placement.userid
where
u.org_id = '555b918ae4b07b6ac5050852'
and u.status IN ( 'active', 'true', '1')
and istestuser != '1'
group by
u.org_id,
t.name,
u.id,
u.name,
o.mode
order by
activity.DistIdCnt desc
FINALLY, your inner queries are querying for ALL users. If you have a large count of users that are NOT active, you MIGHT exclude those users from each inner query by adding those join/criteria there too such as...
( ...
from
lpmysqldb.placements
JOIN lpmysqldb.users u2
on placements.userid = u2.id
and u2.status IN ( 'active', 'true', '1')
and u2.istestuser != '1'
where … ) as placement

MySQL Procedures behaving weird once variables are inserted

I'm having a frustrating time with MySQL and a procedure I'm writing and wanted to see if anyone else had any clues as to what is going on.
The procedure I have below will dynamically transpose rows in a table to columns. It is working perfectly except for the very last WHERE statement.
If I have either of the following WHERE statements it works fine.
WHERE t.company_id = v_company_id AND t.class = 'asset_property'
WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'
However, if I also want to grab records where the company_id could be 1 OR whatever value is passed in, it refuses to run. The only change made to the query is to the 'WHERE` statement. None of these versions will work.
WHERE (t.company_id = v_company_id OR t.company_id = 1) AND t.class = 'asset_property'
WHERE t.company_id IN (v_company_id, 1) AND t.class = 'asset_property'
WHERE t.company_id IN (161, 1) AND t.class = 'asset_property'
Appreciate any assistance that someone more versed in MySQL can provide. I've tried debugging as best I can and the only error I can seem to find is that when I try to get t.company_id to be one of two values, there is a generic error saying Invalid table name.
The full procedure is below.
(See Update 1)
Finally, if I generate the working statement above, then manually add in the lines for t.company_id = 1 records, it works perfectly and creates the following query.
(See Update 1)
Update 1
So that others can simulate what I'm seeing, I've built a test DB with test data in it so you can try this yourself. Also removing some of the code above to save space...
Trying to add this here blew out my character limit. I've uploaded it to my personal site. (Please let me know if this is not a safe thing to do!)
Test DB
Once you've created this DB, here are some procedures and SQL statements that you can run to test it and simulate what I'm doing.
The Procedure fill_tableau_ap that is in the Test DB will run and will create a table with the data in it (but is missing the company 1 records).
That Procedure generates the following SQL:
CREATE TABLE dw_161.tableau_ap AS
SELECT a.id as "Asset ID (ap)",
max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN"
FROM dw_161.equipment AS a
JOIN dw_161.asset_properties ap ON ap.asset_id = a.id
JOIN dw_161.sites AS s on a.site_id = s.id
WHERE dw_161.s.company_id = 161
GROUP BY a.id;
If I manually, add in a single item from company 1 into that above statement as below, I can run this on the DB and it also works. Here's what it looks like in case you also want to run it on the Test DB.
CREATE TABLE dw_161.tableau_ap AS
SELECT a.id as "Asset ID (ap)",
max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
## Next field added manually from company 1 into the query
max(case when ap.property_id = 213 then ap.numeric_value else null end) as "Odometer" ,
max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN"
FROM dw_161.equipment AS a
JOIN dw_161.asset_properties ap ON ap.asset_id = a.id
JOIN dw_161.sites AS s on a.site_id = s.id
WHERE dw_161.s.company_id = 161
GROUP BY a.id;
So we can conclude, that if I can get the statement generated correctly, it will run and work. So it must be a problem with the statement generation.
Breaking the procedure into parts, there is the second half that feeds the list of Asset Properties into the first half. That's where I think things are going haywire. Specifically, in this section of the Procedure:
SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'
ORDER BY ap_name
So what happens if I pull out the variable v_company_id and manually enter what I am ultimately look for and run this, as follows? Well naturally it works and provides a list of all the asset properties. (there are no duplicates here.)
SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (161,1) AND t.class = 'asset_property'
ORDER BY ap_name
Update 2
ARGH!!! Whilst going through all of this and making sure that it was completely repeatable for others looking at it, I noticed one of the fields was registered as decimal in the DB when we store both numeric and decimal data in a single field called numeric_value in the table. That ulitimately was my problem and I appeared to have Rubber Ducked myself. Changing the procedure to translate any fields stored in the DB to the actual column names solved my problem!
Here is the finished procedure in case anyone is interested. It's an interesting bit of code for transposing rows into columns in a DB if others need that.
BEGIN
SET #sql = concat('DROP TABLE IF EXISTS dw_', v_company_id, '.tableau_ap;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET SESSION group_concat_max_len = 1000000;
SET #sql = (select concat('CREATE TABLE dw_', v_company_id, '.tableau_ap AS SELECT a.id as "Asset ID (ap)", ',
group_concat(
concat('max(case when ap.property_id = ',ap_id, ' then ap.', ap_data_type, '_value else null end) as "', ap_name,'" ')
),
'FROM dw_', v_company_id, '.equipment AS a ',
'JOIN dw_', v_company_id, '.asset_properties ap ON ap.asset_id = a.id ',
'JOIN dw_', v_company_id, '.sites AS s on a.site_id = s.id ',
'WHERE dw_', v_company_id, '.s.company_id = ', v_company_id,' ',
'GROUP BY a.id;'
)
from
(
SELECT i.id as ap_id, item as ap_name,
(CASE asset_property_data_type
WHEN 'numeric' THEN 'numeric'
WHEN 'decimal' THEN 'numeric'
WHEN 'calculated' THEN 'numeric'
WHEN 'text' THEN 'text'
WHEN 'date' THEN 'date'
WHEN 'asset' THEN 'id'
WHEN 'employee' THEN 'id'
WHEN 'bar-code' THEN 'text'
WHEN 'currency' THEN 'numeric'
WHEN 'time' THEN 'date'
WHEN 'duration' THEN 'date'
WHEN 'serial' THEN 'text'
END) AS ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (v_company_id,1) AND t.class = 'asset_property'
ORDER BY ap_name) a
)
;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
See Update 2 above in the original post.

MySQL PIVOT and JOIN inner MAX CASE

I have two tables domain and domain_meta. What I want to accomplish is to PIVOT table domain_meta (which Im able to do) and join that table with domain. But I cant wrap my head arround how to join this tables with a PIVOT and MAX CASE. Is the simplest way to use some sort of inner select to my domain_meta table? My code looks like this so far:
domain
SELECT
*
FROM
domain
ORDER BY id
domain_meta
SELECT
id,
domain_id,
source,
MAX(CASE WHEN (meta_key = 'domain') THEN meta_value ELSE NULL END) AS domain,
MAX(CASE WHEN (meta_key = 'ip') THEN meta_value ELSE NULL END) AS ip,
MAX(CASE WHEN (meta_key = 'link') THEN meta_value ELSE NULL END) AS link,
MAX(CASE WHEN (meta_key = 'net') THEN meta_value ELSE NULL END) AS net
FROM
domain_meta
GROUP BY id
ORDER BY id
domain
domain_meta
Something like this -
SELECT
d.id,
d.domain,
MAX(CASE WHEN (dm.meta_key = 'domain') THEN dm.meta_value ELSE NULL END) AS domain,
MAX(CASE WHEN (dm.meta_key = 'ip') THEN dm.meta_value ELSE NULL END) AS ip,
MAX(CASE WHEN (dm.meta_key = 'link') THEN dm.meta_value ELSE NULL END) AS link,
MAX(CASE WHEN (dm.meta_key = 'net') THEN dm.meta_value ELSE NULL END) AS net
FROM
domain d
LEFT JOIN domain_meta dm
ON d.id = dm.domain_id
GROUP BY d.id

How to use user variable as counter with inner join queries that contains GROUP BY statement?

I have 2 tables odds and matches :
matches : has match_id and match_date
odds : has id, timestamp, result, odd_value, user_id, match_id
I had a query that get the following information from those tables for each user:
winnings : the winning bets for each user. (when odds.result = 1)
loses : the lost bets for each user.(when odds.result != 1)
points : the points of each user.(the sum of the odds.odd_value) for each user.
bonus : for each continuous 5 winnings i want to add extra bonus to this variable. (for each user)
How to calculate bonus?
I tried to use this query and I faced a problem : (you can check it here SQL Fiddle)
the calculated bonus are not right for all the users :
first user:(winnings:13, bonus=2).
second user:(winnings:8, bonus=2)bonus here should be 1.
third user:(winnings:14, bonus=3)bonus here should be 2.
why does the query not calculate the bonus correctly?
select d.user_id,
sum(case when d.result = 1 then 1 else 0 end) as winnings,
sum(case when d.result = 2 then 1 else 0 end) as loses,
sum(case when d.result = 1 then d.odd_value else 0 end) as points,
f.bonus
FROM odds d
INNER JOIN
(
SELECT
user_id,SUM(CASE WHEN F1=5 THEN 1 ELSE 0 END) AS bonus
FROM
(
SELECT
user_id,
CASE WHEN result=1 and #counter<5 THEN #counter:=#counter+1 WHEN result=1 and #counter=5 THEN #counter:=1 ELSE #counter:=0 END AS F1
FROM odds o
cross join (SELECT #counter:=0) AS t
INNER JOIN matches mc on mc.match_id = o.match_id
WHERE MONTH(STR_TO_DATE(mc.match_date, '%Y-%m-%d')) = 2 AND
YEAR(STR_TO_DATE(mc.match_date, '%Y-%m-%d')) = 2015 AND
(YEAR(o.timestamp)=2015 AND MONTH(o.timestamp) = 02)
) Temp
group by user_id
)as f on f.user_id = d.user_id
group by d.user_id
I am not sure how your result related to matches table,
you can add back WHERE / INNER JOIN clause if you need.
Here is link to fiddle
and the last iteration according to your comments:
And here is a query:
SET #user:=0;
select d.user_id,
sum(case when d.result = 1 then 1 else 0 end) as winnings,
sum(case when d.result = 2 then 1 else 0 end) as loses,
sum(case when d.result = 1 then d.odd_value else 0 end) as points,
f.bonus
FROM odds d
INNER JOIN
(
SELECT
user_id,SUM(bonus) AS bonus
FROM
(
SELECT
user_id,
CASE WHEN result=1 and #counter<5 AND #user=user_id THEN #counter:=#counter+1
WHEN result=1 and #counter=5 AND #user=user_id THEN #counter:=1
WHEN result=1 and #user<>user_id THEN #counter:=1
ELSE
#counter:=0
END AS F1,
#user:=user_id,
CASE WHEN #counter=5 THEN 1 ELSE 0 END AS bonus
FROM odds o
ORDER BY user_id , match_id
) Temp
group by user_id
)as f on f.user_id = d.user_id
group by d.user_id