Rails: Possible to refactor this query? - ruby-on-rails

I have 2 active record relation objects with the code as follow:
#obj1 = User.select('user.X, table2.Y, table2.Z, count (*)')
.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2, 3)
#obj2 = User.select('user.X, table2.Y, count (*)')
.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2)
Basically, the only difference between #obj1 and #obj2 is that #obj2 is not selecting table2.Z column data.
Here is a sample data that I would like both #obj to have:
#obj1
-------------------------------------
user.X table2.Y table2.Z count
-------------------------------------
1 1 A 1
1 1 B 1
2 1 A 1
2 1 B 1
2 1 C 1
#obj2
-------------------------
user.X table2.Y count
-------------------------
1 1 2
2 1 3
Currently the queries above are working fine, but I believe it is possible to further refactor the code? Like having #obj2 to get the records based on #obj1 data without having to do similar sql query? Appreciate if anyone got input on this. Many thanks in advance.

columns = %w(users.X, table2.Y table2.Z count(*))
#obj1 = User.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2, 3)
.select(*columns)
#obj2 = #obj1.select(*(columns - ["table2.Z"]))
A further step in refactoring would be to use Arel to replace the string conditions for portability.

Related

Rename SAS variables in merge

Suppose I have the following dataset lookup:
ID T001 T002 T002 T004 T005
1 0 1 2 3 4
2 1 2 3 4 5
And I want to merge this onto my main dataset main:
proc sql;
create table main as
select a.*, b.*
from main as a
left join lookup as b on a.ID = b.ID;
quit;
However, this will merge the variables at "T001", "T002", "T003" etc.
I am trying to rename the variables with the merge/join, without having to manually rename each of them as there are 100's of these variables in the dataset. I am looking to get something like
ID V1 V2 V3 V4 V5
1 0 1 2 3 4
2 1 2 3 4 5
You can change the variables names dynamically with a simple macro function after the join
data have;
input ID T001 T002 T003 T004 T005;
datalines;
1 0 1 2 3 4
2 1 2 3 4 5
;
%macro rn;
%do i = 1 %to 5;
T00&i. = V&i.
%end;
%mend;
proc datasets lib=work nolist;
modify have;
rename %rn;
run;quit;
EDIT:
data have;
array t T001-T586 (586*100);
run;
%macro rn;
%do i=1 %to 586;
T%sysfunc(putn(&i., z3.)) = V&i.
%end;
%mend;
proc datasets lib=work nolist;
modify have;
rename %rn;
run;quit;

Limit PER user in rails query

So I have a standard users table structure, with a primary id key and what so not and the following persona table:
user_id | persona_id | time_inserted
2 1 x
2 2 x+1
2 3 x+2
1 1 x+3
5 8 x+6
5 9 x+1
What I'd like to do is retrieve the LAST inserted row and limit to ONE per user id. So, in that query, the result I want would be:
[2, 3] because the last inserted for 2 was persona_id 3 (x+2), [1, 1], and [5,8] because the last inserted for 5 was persona_id 8 (x+6)
This is my query:
to_return = Persona.select(to_get).where(to_condition)
This works, but retrieves them all. How can I restrict the query as asked? Thank you very much.
This should work:
to_return = Persona.select(to_get).where(to_condition).group('user_id').having('time_inserted = MAX(time_inserted)')
Update
You can't select a column if you don't put that in the group clause.
As you want to group by only user_id, one possible solution is, select the user_id s first with the maximum time_inserted like this:
users_ids_relation = Persona.select('user_id').group('user_id').having('time_inserted = MAX(time_inserted)')
Then, join it with the personas table based on the condition and then select the required columns:
users_ids_relation.joins('personas').where(to_condition).select(to_get)
It will give you the expected result.

How can i count a column doing a condition?

i'm trying to count a column using conditions
Tables
select* from policies
|policies|
|id| |client_id| |expiration_date
1 1 2013-10-10
2 1 2013-10-10
3 2 2013-10-10
|clients|
|id| |name|
1 ABC
2 CDE
3 EFG
i WANT
select *,count(number_expirations) from policies where(client=1)
select *,count(number_expirations) from policies where(client=2)
|policies|
|id| |client_id| |number_of_expirations|
1 1 2
3 2 1
This is consult
#count = Policy.count('expiration_date',:joins=> :client,:conditions=>['name =?',params[:name])
But i'm trying to count expiration_date by client_id
I will really appreciate help.
i did not completely understand your question or the finder that you provided, but i think that you want to get a count of expiration_dates grouped by client.
this would look like this:
Policy.where(name: params[:name]).group(:client_id).count

Delphi sort by sum of three fields - delphi

I have a database (*.mdb), scheme of connection, that I use in my program:
TADOConnection -> TADOTable
DB has a table named Table1, which is connected by ADOTable. In Table1 there are fields A, B, C - floating point values. I need to sort the table by sums of these numbers.
For example:
Name A B C
------ --- --- ---
John 1 2 5
Nick 1 5 3
Qwert 1 5 2
Yuiop 2 3 1
I need to sort them, so the name, which A+B+C is bigger, would be first.
Sorted variant:
Name A B C
------ --- --- ---
Nick 1 5 3
John 1 2 5
Qwert 1 5 2
Yuiop 2 3 1
How to do this ?
While writing this, I understood what to do: I need a calculated field in the table, which is equal to A+B+C, and I must sort the table using it.
I do not have MS Access but with other Data Base Systems, I would use SQL to achieve this:
There are several SO answers along these lines for MS Access (try Microsoft Access - grand total adding multiple fields together)
So start with something like this:
Select Name, (A+B+C) as total, A, B, C
from table1
order by total desc

How to store word compositions in a relational database in a normalized way?

I'm trying to find a nice way to store word compositions of the following form:
exhaustcleaningsystem
exhaust cleaning system
exhaustcleaning system
exhaust cleaningsystem
The combinations are given by a default per case. Every word in a composition is stored as a unique row in table 'labels'.
labels
id value
--------------------------
1 exhaustcleaningsystem
2 exhaust
3 cleaning
4 system
5 exhaustcleaning
6 cleaningsystem
I thought about a new table called 'compositions':
compositions
id domain_id range
----------------------
1 1 2,3,4
2 1 5,4
etc...
But storing multiple separated values in a column isn't normalized design. Any ideas for that?
BTW: I'm using MySQL und ActiveRecord/Rails.
The design you propose is not even in first normal form, since range is not atomic
The schema I'd use here would be
compositions
id domain_id
-------------
1 1
2 1
compositions-content
composition_id rank label_id
------------------------------------------
1 1 2
1 2 3
1 3 4
2 1 5
2 2 4
with composition_id referencing an composition.id and label_id referencing label.id
The rank column is optional and should be here if and only if the range you define here is order-sensitive.
With this design, you have some referential integrity at DB level.
Well, this is as far as I can think of in terms of normalisation:
sets
id domain_id
--------------
1 1
2 1
etc...
compositions
id set_id label_id order
---------------------------
1 1 2 1
2 1 3 2
3 1 4 3
4 2 5 1
5 2 4 2
etc...

Resources