I'm trying to fetch data from table where I'm using a CASE condition in the WHERE clause and currently I'm using following query:-
$sQuery = "SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ",
implode(", ", $aColumns))." FROM (select CASE when r.agent_id=24
THEN r.Unit ELSE '--' END AS MyUnit,
CASE when r.agent_id=24 THEN r.landlord_name ELSE '--' END AS landlord_name_new,
r.*,l.loc_name as location,sl.sub_sub_loc as sub_location,
c.category as category,CONCAT(u.first_name, ' ', u.last_name) As agent
from crm_sales r
LEFT JOIN crm_location l ON r.area_location_id=l.loc_id
LEFT JOIN crm_subloc sl ON sl.sub_loc_id = r.sub_area_location_id
LEFT JOIN crm_category c on c.id = r.category_id
LEFT JOIN crm_users u on u.id=r.agent_id
where r.is_active=1 AND r.is_archive=0
AND CASE agent_id WHEN r.agent_id!=24 then r.status=2 else 1=1
group by r.ref) sel
$sWhere
$sOrder
$sLimit
";
Now I want to add one more condition, something like this.
IF(r.agent_id != 24) THEN WHERE r.status=2
EDITED: ADD CASE which i want but error
Fix the case/when clause in your WHERE clause to...
AND CASE WHEN r.agent_id != 24
then r.status = 2
else 1 = 1 end
Related
So I'm trying to get some total numbers of different tables in the database.
This is the query that I'm using
$this->db->select('
c.*,
SUM(rm.discount_value) as totalDiscount,
SUM(a.status = 0) as totalVisits,
SUM(a.status != 0) as totalAnnulations,
SUM(r.treatment_price + r.arrangement_price + r.product_price) + c.start_rev as totalRevenue
')
->join('customers c','c.customer_id = a.customer_id','left')
->join('revenue r','r.customer_id = a.customer_id','left')
->join('remarks rm','rm.customer_id = a.customer_id','left')
->from('agenda a')
->where('a.user_id',$user_id)
->where('a.customer_id',$customer_id)
->group_by('a.customer_id');
This results in the following query.
SELECT `c`.*,
SUM(rm.discount_value) as totalDiscount,
SUM(a.status = 0) as totalVisits, SUM(a.status != 0) as totalAnnulations,
SUM(r.treatment_price + r.arrangement_price + r.product_price) + c.start_rev as totalRevenue
FROM (`agenda` a)
LEFT JOIN `customers` c ON `c`.`customer_id` = `a`.`customer_id`
LEFT JOIN `revenue` r ON `r`.`customer_id` = `a`.`customer_id`
LEFT JOIN `remarks` rm ON `rm`.`customer_id` = `a`.`customer_id` WHERE `a`.`user_id` = '9' AND `a`.`customer_id` = '4134'
GROUP BY `a`.`customer_id`
This query is returning 4810 visits, but there are only 74.
This returns too many results. Its like its not using that a.customer_id
Any help is welcome, thanks in advance.
You are using GROUP BY with a column that does not appear in the SELECT. See how to use GROUP BY.
I have a query that works well, where i would like an assistance is how to incorporate a condition to determine the value displayed on a given column. That is if a column of a table has a value say "Authorization of COA" then the column date added should show the date else the column should show null
Here is my query so far
SELECT r.request_id, r.product_name, r.created_at, r.can,a_s.stat, r.client_id, CONCAT(u.fname,' ',u.lname) 'analyst' , t.date_added (//should show the value of date_added else NULL based on a condition for this column),
FROM request r
LEFT OUTER JOIN assigned_samples a_s ON r.request_id = a_s.labref
LEFT OUTER JOIN user u ON a_s.analyst_id = u.id
LEFT OUTER JOIN tracking_table t ON r.request_id = t.labref
WHERE r.client_id='$cid'
AND r.created_at BETWEEN '$start' AND '$end'
AND a_s.department_id = '$dept'
GROUP BY r.request_id
ORDER BY `r`.`created_at` DESC "
A simple CASE statement should be sufficient in this case, I believe.
SELECT r.request_id, r.product_name, r.created_at, r.can,a_s.stat, r.client_id,
CONCAT(u.fname,' ',u.lname) 'analyst',
CASE WHEN ConditionColumn = 'Authorization of COA' THEN t.date_added
ELSE NULL END AS 'date_added'
FROM request r
LEFT OUTER JOIN assigned_samples a_s ON r.request_id = a_s.labref
LEFT OUTER JOIN user u ON a_s.analyst_id = u.id
LEFT OUTER JOIN tracking_table t ON r.request_id = t.labref
WHERE r.client_id='$cid'
In both mysql and ms sql you can use case expression (mysql case; ms sql case) to assign value to a field conditionally:
SELECT r.request_id, r.product_name, r.created_at, r.can,a_s.stat, r.client_id, CONCAT(u.fname,' ',u.lname) 'analyst' ,
CASE WHEN Column_To_Test = 'Authorization of COA' THEN t.date_added
ELSE null
END AS date_added
FROM request r
LEFT OUTER JOIN assigned_samples a_s ON r.request_id = a_s.labref
LEFT OUTER JOIN user u ON a_s.analyst_id = u.id
LEFT OUTER JOIN tracking_table t ON r.request_id = t.labref
WHERE r.client_id='$cid'
AND r.created_at BETWEEN '$start' AND '$end'
AND a_s.department_id = '$dept'
GROUP BY r.request_id
ORDER BY `r`.`created_at` DESC "
This way the solution is more portable between the databases. Mysql offers if() function, ms sql iif() to achieve the above, but those are product specific solutions.
Try to use the Case statements like.
CASE WHEN ( Condition_1 AND Condition_2 OR ... Condition_N) THEN (Value_1) ELSE (Value_1) END
Here Condition_1 can be column record value and its combination of Column record values
and Value_1 can be single value [Ex: Null or "some string"] or Returned value from nested sql statement like [Ex: (select count(*) from ...)]
Give this a try:
SELECT r.request_id, r.product_name, r.created_at, r.can,a_s.stat, r.client_id, CONCAT(u.fname,' ',u.lname) 'analyst' ,
IFF(nameOfColumnToTest = 'Authorization of COA', t.date_added, null) AS DateAdded
FROM request r
LEFT OUTER JOIN assigned_samples a_s ON r.request_id = a_s.labref
LEFT OUTER JOIN user u ON a_s.analyst_id = u.id
LEFT OUTER JOIN tracking_table t ON r.request_id = t.labref
WHERE r.client_id='$cid'
AND r.created_at BETWEEN '$start' AND '$end'
AND a_s.department_id = '$dept'
GROUP BY r.request_id
ORDER BY `r`.`created_at` DESC "
Here's my current query:
$q = "SELECT u.uid,CONCAT_WS(' ', u.first_name, u.last_name) name, CASE WHEN t.name IS NULL THEN 0 ELSE t.name END AS teamname ";
$q .= "FROM {$users} ";
$q .= "LEFT JOIN {$schedule} ON u.uid = s.uid ";
$q .= "LEFT JOIN {$products} ON p.admitting_id = u.uid ";
$q .= "LEFT JOIN {$teams} ON t.id = s.team ";
$q .= "WHERE (u.uid = {$current_user_id} AND u.roles = 'hoa') OR ";
$q .= "(p.id={$pid} AND p.admitting_id != 0) OR ";
$q .= "(t.admitting = 1 AND s.inactive != 1 AND s.role = 'hoa' AND (s.date = '{$today}' OR (s.date = '{$yesterday}' AND t.overnight = 1))) ";
$q .= "ORDER BY u.last_name,u.first_name,t.name";
What I need to get is:
Current User, if Current User has role hoa
User where uid matches admitting_id from products table
All users with role hoa who are scheduled today or were scheduled yesterday on an overnight shift. With those scheduled users, I need the names of the team they were/are scheduled with. Duplicate uids is good because I need all the different team names if they were scheduled on multiple teams.
What I don't need to get is:
Team name for options 1 and 2 above.
What I'm getting is:
Everything perfect for #3 above.
All possible team names for #1 and #2 above, whereas I want the team names to be 0 if they're not on the schedule.
I could split this up into three queries but that's not preferable.
Sometimes formatting the query out a bit helps visualise. It doesn't need to become three queries, I agree.
Can you provide some sample schema and data, ideally both in the question description and on something like sqlfiddle for us to play with?
It's hard to visualise your structure and data, but I'm speculating the issue is every record in users table is joining to schedule with the on clause you've used.
You could move the logic of condition 3 into the on clause (it's a left join, so nothing else will break) or duplicate it in the CASE statement in the SELECT:
$q = <<<SQL
SELECT
u.uid,
CONCAT_WS(' ', u.first_name, u.last_name) name,
IF(
WHEN t.name IS NULL THEN
0
ELSE
t.name
END AS teamname
FROM {$users} AS u
LEFT JOIN {$schedule} AS s ON (u.uid = s.uid)
LEFT JOIN {$products} AS p ON (p.admitting_id = u.uid)
LEFT JOIN {$teams} AS t ON
(
t.id = s.team AND
t.admitting = 1 AND
s.inactive != 1 AND
s.role = 'hoa' AND
(
s.date = '{$today}'
OR
(
s.date = '{$yesterday}' AND
t.overnight = 1
)
)
)
WHERE
( -- 1: Current User, if Current User has role hoa
u.uid = {$current_user_id} AND
u.roles = 'hoa'
)
OR
( -- 2: User where uid matches admitting_id from products table
p.id={$pid} AND
p.admitting_id != 0
)
OR
t.name IS NOT NULL
ORDER BY
u.last_name,
u.first_name,
t.name
SQL;
I'm absolutely not certain that'll fix your problem without something real to play with... Happy to continue looking if you can provide a working example sandpit.
I am using Rails 3.2.13, Mysql, Sql to filter records. Search is working perfect. But it is taking more time (more than a minute) to return result.
I cannot use eager loading here because raw sql query with join is used and i cannot use cache because our records will change frequently as per filters. FYI i have already used indexes in tables.
Any solution would be appreciated. Thanks in advance.
My Controller:
class ProjectReportsController < ApplicationController
def index
#results = ProjectCustomValueSearch.new(params[:teams], params[:contract_types], params[:retainer_ends], params[:retainer_ends_date], params[:status]).search
end
end
My Model:
class ProjectCustomValueSearch
attr_reader :teams, :contract_types, :retainer_ends, :retainer_ends_date, :status
def initialize(teams, contract_types, retainer_ends, retainer_ends_date, status)
#teams = teams
#contract_types = contract_types
#retainer_ends = retainer_ends
#retainer_ends_date = retainer_ends_date
#status = status
end
def search
#add status filter condition
status_query = (#status=='Both' || #status.blank?) ? " p.status = 1 OR p.status = 5" : " p.status = #{ActiveRecord::Base.sanitize(#status)}"
other_conditions = ''
#add team filter condition
if (#teams!='DM' && #teams!='Web')
other_conditions += " AND cv_team.value #{all_none_condition(#teams, 'cv_team.value')}"
elsif (#teams=="DM" || #teams=="Web")
other_conditions += " AND #{dm_or_web_condition(#teams)}"
end
#add cv_contract_type filter condition
other_conditions += " AND cv_contract_type.value #{all_none_condition(#contract_types, 'cv_contract_type.value')}"
#add cv_retainer_end value and cv_retainer_end date filter conditions
other_conditions += " AND cv_retainer_end.value #{before_after_condition(#retainer_ends_date, #retainer_ends)}" if #retainer_ends_date.present?
#Sql query is something like this:
sql = <<-sql
select p.id, p.name as project_name,
u_web_pm.firstname as web_pm_firstname,
u_web_pm.lastname as web_pm_lastname,
concat(u_marketing_pm.firstname, ' ', u_marketing_pm.lastname) as marketing_pm_value,
u_client_contact.firstname as client_contact_firstname,
u_client_contact.lastname as client_contact_lastname,
FORMAT(Round(cv_monthly_retainer.value, 0), 0) as monthly_retainer_value,
FORMAT(Round(cv_project_budget.value, 0), 0) as project_budget_value,
cv_rates.value as rates_value,
cv_retainer_start.value as retainer_start_value,
cv_retainer_end.value as retainer_end_value,
cv_contract_type.value as contract_type_value,
cv_team.value as team_value,
cv_discount.value as discount_value,
cv_account_rep.value as account_rep_value,
FORMAT(Round(cv_project_budget.value / 150, 0), 0) as budget_project,
FORMAT(Round(cv_monthly_retainer.value / 150, 0), 0) as budget_retainer,
FORMAT(Round(sum(time_entry.hours), 0), 0) as total_hours
from projects p
#Web PM
left join custom_values as cv_web_pm on p.id = cv_web_pm.customized_id and cv_web_pm.custom_field_id=4
left join users as u_web_pm on cv_web_pm.value = u_web_pm.id
#Marketing PM
left join custom_values as cv_marketing_pm on p.id = cv_marketing_pm.customized_id and cv_marketing_pm.custom_field_id=5
left join users as u_marketing_pm on cv_marketing_pm.value = u_marketing_pm.id
#Client Contact
left join custom_values as cv_client_contact on p.id = cv_client_contact.customized_id and cv_client_contact.custom_field_id=6
left join users as u_client_contact on cv_client_contact.value = u_client_contact.id
#Monthly Retainer
left join custom_values as cv_monthly_retainer on p.id = cv_monthly_retainer.customized_id and cv_monthly_retainer.custom_field_id=7
#Project Budget
left join custom_values as cv_project_budget on p.id = cv_project_budget.customized_id and cv_project_budget.custom_field_id=8
#Rates
left join custom_values as cv_rates on p.id = cv_rates.customized_id and cv_rates.custom_field_id=9
#Retainer Start
left join custom_values as cv_retainer_start on p.id = cv_retainer_start.customized_id and cv_retainer_start.custom_field_id=10
#Retainer End
left join custom_values as cv_retainer_end on p.id = cv_retainer_end.customized_id and cv_retainer_end.custom_field_id=11
#Contract Type
left join custom_values as cv_contract_type on p.id = cv_contract_type.customized_id and cv_contract_type.custom_field_id=12
#Team
left join custom_values as cv_team on p.id = cv_team.customized_id and cv_team.custom_field_id=13
#additional filters
where #{status_query}
#{other_conditions}
Group BY p.id
order by p.name ASC
sql
ActiveRecord::Base.connection.execute(sql)
end
private
def all_none_condition(str, field='')
case str
when 'All'
return " = '' or #{field} <> '' "
when 'Any'
return " <> '' "
when 'None'
return " = '' "
else
return " = #{ActiveRecord::Base.sanitize(str)}"
end
end
def dm_or_web_condition(str)
case str
when 'DM'
return " (cv_team.value='DM 1' OR cv_team.value='DM 2') "
when 'Web'
return " (cv_team.value='Web 1' OR cv_team.value='Web 2') "
end
end
def before_after_condition(date, condition)
case condition
when 'Before'
return " < #{ActiveRecord::Base.sanitize(date)} and cv_retainer_end.value <> ''"
when 'After'
return " > #{ActiveRecord::Base.sanitize(date)} and cv_retainer_end.value <> ''"
end
end
end
guys I cant figure this out.. I red a lot but no luck...
I have the following query, and I need to limit it in order to show the total results minus a specific number os results, let's say 10.
I mean, if the query would return 1000 total results, I want it to return 990, and the last 10 results need to be excluded.
Is this possible?
see the query call:
$query = ' SELECT p.*,c.name as name_category,t.name as name_type,cy.name as name_country,s.name as name_state,l.name as name_locality,l.alias as locality_alias,pf.name as name_profile, '
. ' CASE WHEN CHAR_LENGTH(p.alias) THEN CONCAT_WS(":", p.id, p.alias) ELSE p.id END as Pslug,'
. ' CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(":", c.id, c.alias) ELSE c.id END as Cslug,'
. ' CASE WHEN CHAR_LENGTH(cy.alias) THEN CONCAT_WS(":", cy.id, cy.alias) ELSE cy.id END as CYslug,'
. ' CASE WHEN CHAR_LENGTH(s.alias) THEN CONCAT_WS(":", s.id, s.alias) ELSE s.id END as Sslug,'
. ' CASE WHEN CHAR_LENGTH(l.alias) THEN CONCAT_WS(":", l.id, l.alias) ELSE l.id END as Lslug, '
. ' CASE WHEN CHAR_LENGTH(t.alias) THEN CONCAT_WS(":", t.id, t.alias) ELSE t.id END as Tslug '
. ' FROM #__properties_products AS p '
. ' LEFT JOIN #__properties_country AS cy ON cy.id = p.cyid '
. ' LEFT JOIN #__properties_state AS s ON s.id = p.sid '
. ' LEFT JOIN #__properties_locality AS l ON l.id = p.lid '
. ' LEFT JOIN #__properties_profiles AS pf ON pf.mid = p.agent_id '
. ' LEFT JOIN #__properties_category AS c ON c.id = p.cid '
. ' LEFT JOIN #__properties_type AS t ON t.id = p.type '
. ' WHERE p.published = 1 '
.' ORDER BY p.id DESC '
;
If you are using MySQL, then use limit and offset:
limit 10, 9999999
This starts at the 10th record and continues to the end of the data (or to 9999999 rows, technically).
You are ordering by p.id desc, so this will remove the 10 rows with the highest id.
To really do what you seem want (remove the 10 with the lowest id), use a subquery and then sort again after the subquery:
select t.*
from (<most of your query here>
order by p.id asc
limit 10, 999999
) t
order by id desc
To remove the rows with the highest id, just add the limit statement:
$query = 'SELECT p.*,c.name as name_category,t.name as name_type,cy.name as name_country,s.name as name_state,l.name as name_locality,l.alias as locality_alias,pf.name as name_profile, '
. ' CASE WHEN CHAR_LENGTH(p.alias) THEN CONCAT_WS(":", p.id, p.alias) ELSE p.id END as Pslug,'
. ' CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(":", c.id, c.alias) ELSE c.id END as Cslug,'
. ' CASE WHEN CHAR_LENGTH(cy.alias) THEN CONCAT_WS(":", cy.id, cy.alias) ELSE cy.id END as CYslug,'
. ' CASE WHEN CHAR_LENGTH(s.alias) THEN CONCAT_WS(":", s.id, s.alias) ELSE s.id END as Sslug,'
. ' CASE WHEN CHAR_LENGTH(l.alias) THEN CONCAT_WS(":", l.id, l.alias) ELSE l.id END as Lslug, '
. ' CASE WHEN CHAR_LENGTH(t.alias) THEN CONCAT_WS(":", t.id, t.alias) ELSE t.id END as Tslug '
. ' FROM #__properties_products AS p '
. ' LEFT JOIN #__properties_country AS cy ON cy.id = p.cyid '
. ' LEFT JOIN #__properties_state AS s ON s.id = p.sid '
. ' LEFT JOIN #__properties_locality AS l ON l.id = p.lid '
. ' LEFT JOIN #__properties_profiles AS pf ON pf.mid = p.agent_id '
. ' LEFT JOIN #__properties_category AS c ON c.id = p.cid '
. ' LEFT JOIN #__properties_type AS t ON t.id = p.type '
. ' WHERE p.published = 1 '
.' ORDER BY p.id desc limit 10, 999999'
;