Sum all attributes in a model? - sql

I was curious if there is an easy way to sum all attributes in a model without it looking repetitive, and not DRY.
I have a donation app, and this is how I summed everything:
def self.total_donations
array = Category.pluck(
'SUM(toilet_paper)',
'SUM(dental_hygiene)',
'SUM(first_aid)',
'SUM(general_hygiene)',
'SUM(underwear_socks)',
'SUM(blankets)',
'SUM(school_supplies)',
'SUM(diapers)').flatten.compact
array.inject(0){|sum, x| sum + x}
end
It's just ugly, but I don't know how to get around adding all of them up without doing something like this.
Thanks!

Check out this one:
def self.total_donations
sum("toilet_paper + dental_hygiene + first_aid + general_hygiene + underwear_socks + blankets + school_supplies + diapers")
end
The generated SQL:
SELECT SUM(toilet_paper + dental_hygiene + first_aid + general_hygiene + underwear_socks + blankets + school_supplies + diapers)
FROM "categories"
short (no shorter possible)
efficient (all the processing is done on the database layer)
Note, that in the class instance methods you don't have to use Category, because it is self (assuming, the method is in the Category model).

Related

How to Convert SQL to Laravel Query

I want to build something with an aliases column like below, but I don't know how to make it a Laravel query. The following is my SQL.
SELECT
d.*,
d.damaged_building,
d.total_victim
FROM
(
SELECT
delete_flg,
damage_id,
create_time,
reg_user_name,
municipality_id,
report_time,
district,
village,
disaster_type,
cause_of_disaster,
(
bd_major_damage1 + bd_minor_damage1 + bd_major_damage2 + bd_minor_damage2 + bd_major_damage3 + bd_minor_damage3
)
as damaged_building,
(
hi_hd_deaths + hi_hd_serious_injuries + hi_hd_minor_injuries + hi_hd_missing_persons + hi_hd_sick_persons
)
as total_victim
FROM
d_damage
WHERE
delete_flg = 0
ORDER BY
create_time DESC
)
d
I want to translate this to Eloquent of Laravel Query Builder for use in my controller.
You may try with this
DB::table('d_damage')
->where('delete_flg',0)
->orderBy('create_time', 'desc')
->select('delete_flg', 'damage_id', 'create_time', 'reg_user_name', 'municipality_id', 'report_time', 'district', 'village', 'disaster_type', 'cause_of_disaster',DB::raw('(bd_major_damage1 + bd_minor_damage1 + bd_major_damage2 + bd_minor_damage2 + bd_major_damage3 + bd_minor_damage3) as damaged_building'),DB::raw('(hi_hd_deaths + hi_hd_serious_injuries + hi_hd_minor_injuries + hi_hd_missing_persons + hi_hd_sick_persons) as total_victim'))
->get();
this may be not exactly but almost
If I were you just stick to learning the SQL Queries since you bring it anywhere you can learn alot of frameworks / tools, rather than investing your time in Laravel's. Anyway, you still can use sql queries in laravel using the raw expressions : https://laravel.com/docs/5.8/queries#raw-expressions

Can't get delphi SQL LIKE to work with %

I'm doing a school project and need to code a query to filter a dataset to certain variables. All my SQL works fine, except I can't get the LIKE statement to work with %-signs. I believe my syntax is wrong. Can anybody please tell me what I'm doing wrong. Thanks
The code:
qryMovie.SQL.Clear;
qryMovie.SQL.Add('SELECT * FROM Movies');
qryMovie.SQL.Add('WHERE Genre = ' + QuotedStr(genre));
qryMovie.SQL.Add('AND Price BETWEEN ' + minPrice + ' AND ' + maxPrice);
qryMovie.SQL.Add('AND Title LIKE %' + title + '%');
qryMovie.Open;
Error produced:
'Syntax error in query expression 'Genre = 'Action/Adventure'
AND Price BETWEEN 0 AND 200
AND Title LIKE %Star Wars%''
LIKE %Star Wars%
but you need
LIKE '%Star Wars%'
You need to quote % with ':
qryMovie.SQL.Add(' AND Title LIKE ''%' + title + '%''');
Anyway you should use binded parameters instead of concatenating SQL string. It is error-prone and could lead to SQL Injection attacks.

Tableau Calculated Fields IF THEN Statement adding multiple fields

I'm exploring Consumer Expenditure microdata (individual level data) from BLS and I'm looking to create a new field for investable assets by adding a number of different fields and bucketing respondents into $250K+ and <$250K. I'm using Tableau Public.
My formula is below. Various fields are things like total value of stock holdings, retirement accounts, checking & saving accounts, etc.
If [Irax] + [Irabx] + [Liquidb] + [Liquidbx] + [Othastx] + [Othastbx] + [Stockbx] + [Stockx] >= 250000 THEN "$250K+"
ELSEIF [Irax] + [Irabx] + [Liquidb] + [Liquidbx] + [Othastx] + [Othastbx] + [Stockbx] + [Stockx] > 250000 THEN "<$250K"
END
The calculation is valid, however the result is not accurate. The formula buckets everyone into the >$250K bucket, even though there are clearly individuals that have over that amount.
What is happening here?
Define a field called investable assets =
[Irax] + [Irabx] + [Liquidb] + [Liquidbx] + [Othastx] + [Othastbx] + [Stockbx] + [Stockx]
Then define a numeric parameter called [investment threshold] defaulting to 250000
Then finally a calculated field called rich guy =
SUM([investable assets]) > [investment threshold]
Now you can use [rich guy] as desired, and tweak your parameter interactively.
There are other variations, you could use LOD calcs or sets instead. You can define an alias for [rich guy] to display "Loaded and Broke" instead of "True and False". But this is a typical approach for spotlighting.
BTW, the only thing that is especially different than your approach is the use of the function SUM()

iif blank show zero

I have a visual studio report that I want to state that if a calculation box is blank due to there being no figures available on that particluar project then show zero.
My calculation is :- =((Sum(Fields!TotalCost.Value, "Accrued") + Sum(Fields!TotalCost.Value, "serv1")) /
(Sum(Fields!Quantity.Value, "serv1") + Sum(Fields!Quantity.Value, "Accrued"))
)
And I want to try and include an IIF statement in that to show zero if blank.
Any ideas on how to best achieve my aim?
so far I have got to
=iif((Sum(Fields!TotalCost.Value, "Accrued") + Sum(Fields!TotalCost.Value, "serv1")) /
(Sum(Fields!Quantity.Value, "serv1") + Sum(Fields!Quantity.Value, "Accrued"))
) = "" ,false,0 ) but I am getting a little confused.
Most likely value is not blank string but a Nothing. Try following construct:
=IIf(IsNothing(((Sum(Fields!TotalCost.Value, "Accrued") + Sum(Fields!TotalCost.Value, "serv1")) / (Sum(Fields!Quantity.Value, "serv1") + Sum(Fields!Quantity.Value, "Accrued"))), 0, ((Sum(Fields!TotalCost.Value, "Accrued") + Sum(Fields!TotalCost.Value, "serv1")) / (Sum(Fields!Quantity.Value, "serv1") + Sum(Fields!Quantity.Value, "Accrued")))
It's a bit awkward since you have to repeat the expression twice, to avoid it you may want to write a custom function.

Efficient way to update multiple records with independent values?

I have the following (overly db expensive) method:
def reorder_area_routes_by_demographics!
self.area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).readonly(false).each_with_index do |area_route, i|
area_route.update_attributes(match_rank: i)
end
end
But this results in an UPDATE query for each area_route. Is there a way to do this in one query?
--Edit--
Final solution, per coreyward suggestion:
def reorder_area_routes_by_demographics!
sorted_ids = area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).pluck(:'area_routes.id')
AreaRoute.update_all [efficient_sort_sql(sorted_ids), *sorted_ids], {id: sorted_ids}
end
def efficient_sort_sql(sorted_ids, offset=0)
offset.upto(offset + sorted_ids.count - 1).inject('match_rank = CASE id ') do |sql, i|
sql << "WHEN ? THEN #{id} "
end << 'END'
end
I use the following to do a similar task: updating the sort positions of a bevy of records according to their order in params. You might need to refactor or incorporate this differently to accomodate the scopes you're applying, but I think this will send you in the right direction.
def efficient_sort_sql(sortable_ids, offset = 1)
offset.upto(offset + sortable_ids.count - 1).reduce('position = CASE id ') do |sql, i|
sql << "WHEN ? THEN #{i} "
end << 'END'
end
Model.update_all [efficient_sort_sql(sortable_ids, offset), *sortable_ids], { id: sortable_ids }
sortable_ids is an array of integers representing the ids of each object. The resulting SQL looks something like this:
UPDATE pancakes SET position = CASE id WHEN 5 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 3 WHEN 1 THEN 4 WHEN 2 THEN 5 WHERE id IN (5,3,4,1,2);
This is, ugliness aside, a pretty performant query and (at least in Postgresql) will either fully succeed or fully fail.