PG::InvalidColumnReference: ERROR when sorting by associated table - mysql

I'm trying to sort/order a table (Employer) based on the number of associated records (Employee) each (Employer) has.
The following code works on rails console with the Employer records sorted by number of Employees as intended :
Employer.joins(:employees).group(:id).order('count(employees.id) ASC')
However, when actually trying to run this on development, I get this error:
PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
While I could use 'sort_by", I would prefer to have the result in ActiveRecord::Relation format. Any help would be appreciated.

I was able to reproduce this error in the console by adding distinct to the expression:
In your case it would be:
Employer.distinct.joins(:employees).group(:id).order('count(employees.id) ASC')
The error message says that you have to add the expression you sort by (count(employees.id)) to the select list.
That could be achieved by explicitly specifying select columns:
Employer.select('employers.id, count(employees.id)').joins(:employees).group(:id).order('count(employees.id) ASC')

Related

cannot access field on a value with type string_google big query

I faced an error in google big query that I haven't been successful to find a solution for that.
I have two tables, Airnow_dataset.adjustedTime_met_la_wind_letter and Airnow_dataset.station_neighbour, the value of wind_direction column in the former table defines the column name of the latter one.
I used "case" clause to refer to the appropriate columns of another table, but an error comes up whenever I run query
cannot access field pm_station on a value with type string at [3:83]
I would like to mention that the number of rows returned in station_neighbour is one, so it shouldn't be a problem. Also, when I hardcoded s.pm_station value, it works fine. I guess the problem is due to aliasing in the outer query, but I don't know how I can fix it. For your information, I have attached the screenshot of my tables as well as my code.
Any help is greatly appreciated.
This is my query:
SELECT s.pm_station, s.RH, (CASE
WHEN s.wind_direction="W" then (SELECT ss.W FROM
`Airnow_dataset.station_neighbour` ss
WHERE ss.pm_station=s.pm_station )
ELSE "na"
END) as neighbour_wind_direction
FROM `Airnow_dataset.adjustedTime_met_la_wind_letter` s
This is image of schemas:
The problem is that your station_neighbour table has a column named S, so the outer alias for adjustedTime_met_la_wind_letter is shadowed within the CASE WHEN expression. To work around the error, use a different alias, e.g.:
SELECT
wind_letter.pm_station,
wind_letter.RH,
(CASE WHEN wind_letter.wind_direction="W" THEN (
SELECT ss.W FROM
`Airnow_dataset.station_neighbour` ss
WHERE ss.pm_station=wind_letter.pm_station )
ELSE "na" END) as neighbour_wind_direction
FROM `Airnow_dataset.adjustedTime_met_la_wind_letter` wind_letter

QSqlRecord: Access numeric value from SQLite Table in QT, results are empty

The question I have is similar to a few I've seen, but the solutions don't seem to work for me, so I'll add a new one:
I am trying to access a numeric value (the highest user ID) from an SQLite table into my QT Program, with the following query:
SELECT Name, MAX(ID) FROM User_lib;
This works from the command shell, with the expected result.
I then attempt to access the maximal ID value with:
QSqlQuery qry_ID;
qry_ID.prepare("SELECT Name, MAX(User_lib.ID) FROM User_lib");
qry_ID.exec()
qDebug() << qry_ID.record().value("ID").toInt();
The result is zero (and empty if I access "Name" with toString())
Also, as a test
qDebug() << "Number of Rows: " << qry_ID.size();
which I've seen in several other answers gives me -1.
On the other hand,
qDebug() << "Number of columns: " << qry_ID.record().count();
gives me "Number of columns 2" as expected. It appears that the query gives no results.
At first I thought that I had a problem with my query, but the same thing is happening when I attempt to count the rows in queries that clearly work correctly (table is displayed, I can add elements correctly, etc), so I think I must be doing something wrong in QT.
Let's see what you actually get in the command-line shell:
sqlite> .mode columns
sqlite> .header on
sqlite> SELECT Name, MAX(ID) FROM User_lib;
Name MAX(ID)
---------- ----------
user30248 8562493
So in the output that you get from the query, the second column is not named ID but MAX(ID).
The documentation actually says:
The name of a result column is the value of the "AS" clause for that column, if there is an AS clause. If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next.
So use AS, or access the column by its index.
SQLite computes output rows on demand, so it is not possible to give a count of rows before they have all been read. Therefore, the QuerySize feature is not supported by the SQLite driver.
I haven't checked CL's answer above, which I am sure will work as well, but I have managed to find an alternative solution that worked for me and may be interesting. Since QsqlQuery's internal pointer is set to one field ahead of the first record, I have to advance with next. This is the code that worked:
QSqlQuery qry_ID;
qry_ID.prepare("SELECT Name, MAX(ID) FROM User_lib");
qry_ID.exec();
qry_ID.next();
QString name = qry_ID.value(0).toString();
int IDmax = qry_ID.value(1).toInt();
If you need to access various rows, a while loop is required, but that is a different question.

SUM(IF(COND,EXPR,NULL)) and IF(COND, SUM(EXPR),NULL)

I'm working of generating sql request by parsing Excel-like formulas.
So for a given formula, I get this request :
SELECT IF(COL1='Y', SUM(EXPR),NULL)
FROM Table
I don't get the results I want. If I manually rewrite the request like this it works :
SELECT SUM(IF(COL1='Y', EXPR, NULL))
FROM Table
Also, the first request produces the right value if I add a GROUP BY statement, for COL1='Y' row :
SELECT IF(COL1='Y', SUM(EXPR),NULL)
FROM Table
GROUP BY COL1
Is there a way to keep the first syntax IF(COND, SUM(EXPR), NULL) and slightly edit it to make it works without a GROUP BY statement ?
You have to use GROUP BY since you are using SUM - otherwise SQL engine is not able to tell how do you want to summarize the column.
Alternatively you could summarize this column only:
SELECT SUM(EXPR)
FROM Table
WHERE COL1='Y'
But then you would have to run separate query for each such column, read: not recommended for performance reasons.

Why is my query wrong?

before i use alias for table i get the error:
: Integrity constraint violation: 1052 Column 'id' in field list is ambiguous
Then i used aliases and i get this error:
unknown index a
I am trying to get a list of category name ( dependant to a translation) and the associated category id which is unique. Since i need to put them in a select, i see that i should use the lists.
$categorie= DB::table('cat as a')
->join('campo_cat as c','c.id_cat','=','a.id')
->join('campo as d','d.id','=','c.id_campo')
->join('cat_nome as nome','nome.id_cat','=','a.id')
->join('lingua','nome.id_lingua','=','lingua.id')
->where('lingua.lingua','=','it-IT')
->groupby('nome.nome')
->lists('nome.nome','a.id');
The best way to debug your query is to look at the raw query Laravel generates and trying to run this raw query in your favorite SQL tool (Navicat, MySQL cli tool...), so you can dump it to log using:
DB::listen(function($sql, $bindings, $time) {
Log::info($sql);
Log::info($bindings);
});
Doing that with yours I could see at least one problem:
->where('lingua.lingua','=','it-IT')
Must be changed to
->where('lingua.lingua','=',"'it-IT'")
As #jmail said, you didn't really describe the problem very well, just what you ended up doing to get around (part of) it. However, if I read your question right you're saying that originally you did it without all the aliases you got the 'ambiguous' error.
So let me explain that first: this would happen, because there are many parts of that query that use id rather than a qualified table`.`id.
if you think about it, without aliases you query looks a bit like this: SELECT * FROM `cat` JOIN `campo_cat` ON `id_cat` = `id` JOIN `campo` ON `id` = `id_campo`; and suddenly, MySQL doesn't know to which table all these id columns refer. So to get around that all you need to do is namespace your fields (i.e. use ... JOIN `campo` ON `campo`.`id` = `campo_cat`.`id_campo`...). In your case you've gone one step further and aliased your tables. This certianly makes the query a little simpler, though you don't need to actually do it.
So on to your next issue - this will be a Laravel error. And presumably happening because your key column from lists($valueColumn, $keyColumn) isn't found in the results. This is because you're referring to the cat.id column (okay in your aliased case a.id) in part of the code that's no longer in MySQL - the lists() method is actually run in PHP after Laravel gets the results from the database. As such, there's no such column called a.id. It's likely it'll be called id, but because you don't request it specifically, you may find that the ambiguous issue is back. My suggestion would be to select it specifically and alias the column. Try something like the below:
$categories = DB::table('cat as a')
->join('campo_cat as c','c.id_cat','=','a.id')
->join('campo as d','d.id','=','c.id_campo')
->join('cat_nome as nome','nome.id_cat','=','a.id')
->join('lingua','nome.id_lingua','=','lingua.id')
->where('lingua.lingua','=','it-IT')
->groupby('nome.nome')
->select('nome.nome as nome_nome','a.id as a_id') // here we alias `.id as a_id
->lists('nome_nome','a_id'); // here we refer to the actual columns
It may not work perfectly (I don't use ->select() so don't know whether you pass an array or multiple parameters, also you may need DB::raw() wrapping each one in order to do the aliasing) but hopefully you get my meaning and can get it working.

Rails find_by_sql issue

I have the following call in my RoR script:
Foo.where("event = 'Login'").group('user_id').order('user_id ASC').count()
This gives me a list of all users and how much they have logged in in the form of:
<userid1> => <count>, <userid2> => <count>, ...}
This is great and very close to what I wan but I've been unable to convince it to sort by the count of logins instead, what I'd really like to have it do. There is also a column that has some info about the login session in the form of a character delimited string. I'd like to get at certain parts of that information.
To achieve this I've tried using find_by_sql and when I make the following call:
Foo.find_by_sql("SELECT userid, COUNT(*) AS number, SUBSTRING_INDEX(stuff, ',', 1) AS info FROM <table> WHERE event = 'Login' GROUP BY userid")
What I get is a ilst of Foo entries that contain the userids but not the count or the info. When I run this in the MySQL workbench it works like a charm. Is there something else I need to do to get this to work? Also, would there be a way to just do this using Foo.select or Foo.where? Thanks.
Update I have also tried this format, as demonstrated here:
Foo.find(:all, :select => 'count(*) count, userid', :group =>'userid')
But this too merely responds with the userids and does not spit out the count.
Update 2 Looking at the output a bit more i can see now that when i do the find_by_fql call everything is being found in the correct way and even being sorted. It just isn't actually selecting the COUNT(*) or the SUBSTRING_INDEX.
Update 3 I also tried out this SO tip but when I tell it:
Foo.find(:all, :select => 'userid, count(*) as cnt', :group => 'userid')
It doesn't print or find anything related to the var cnt. I'm totally baffled here because I've seen more than one example now that does it this ^^ way and I've yet to get it to succeed.
Actually, your problem is not an SQL problem. To generate the correct SQL you would just need this:
Foo.where("event = 'Login'").group('user_id').order('count_all').count()
Take a look in your log and you'll find that this generates the following SQL:
SELECT COUNT(*) AS count_all, user_id AS school_id FROM `foos` GROUP BY user_id ORDER BY count_all
...and if you run that in your SQL console you'll get what you want.
The problem is that Rails doesn't return them in this order, Rails always returns these special group/count results in the order of the GROUP BY field. So, if you want them in a different order then you'll need to do it in Ruby after getting the hash back.
Code below returns an array of foos, checking any element inside foo will return userid/cnt
foos = Foo.find(:all, :select => 'userid, count(*) as cnt', :group => 'userid')
Is this what you're looking for?
foos.first.userid # will show userid
foos.first.cnt # will show count