want to get data from mysql as string - mysql

DB::table('follow_ups')
->select(
'created_at as start',
DB::raw('count(*) as title')
)->groupBy('created_at')->get()->toArray();
above query is returning title as integer, i want this value as string

COUNT(*) is an aggregation function that will count distinct titles in a group. If you want to get all titles you need a different aggregation function that can (somehow) return all members of the group. There is one option that is generally available (i.e. even in older MySQL versions):
GROUP_CONCAT
DB::table('follow_ups')
->select(
'created_at as start',
DB::raw('GROUP_CONCAT(title) as title')
)->groupBy('created_at')->get()->toArray();
This will return all group members concatenated via the delimiter you specify (default is , if you don't specify one)
Newer MySQL versions also have JSON_ARRAYAGG
DB::table('follow_ups')
->select(
'created_at as start',
DB::raw('JSON_ARRAYAGG(title) as title')
)->groupBy('created_at')->get()->toArray();
This will return the result as a json array which you can then decode using json_decode($row['title'],true)
The advantage of the 2nd method is that it's easier to get individual values of the group in the cases where the group members contain the delimiter e.g. there's some title that contains a comma and would therefore make GROUP_CONCAT a bit useless.
Note: Both these functions are MySQL/MariaDB specific as far as I know so if you plan to make your database portable you might want to avoid them and look for alternatives that are ANSI SQL compliant.

Related

get distinct "title" in mysql in django

I have used django to develop a web app.
I want to get the distinct "title" form the queryset get by filter.
But I use mysql so could not pass "title" to distict.
How could I filter the queryset with the distinct "title"?
query_set = CourseInfo.objects.filter(discipline_id=id).distinct('title')
return render(request, 'main.html',
context={'query_set':query_set})
I get error for this in mysql as it may only used in postgresql
`
It will give you distinct titles:
titles = CourseInfo.objects.filter(
discipline_id=id
).order_by('title').values('title').distinct()
Note:
there is no such thing called SELECT DISTINCT ON in MySQL.
You can only use it in Postgresql but maybe GROUP BY helps you for converting SELECT DISTINCT ON query to MySQL query.
Check out this link then you kinda can convert this query to MySQL query.

how to sort varchar column containing numeric values with linq lambdas to Entity

I am using linq lambdas to query the MySql (Note MySql not Sql) with Entity Framwork in MVC. Now i have one table product one of column this table is price with datatype "VARCHAR" (Accept i can't change type to INT as it can hold values like "N/A",etc).
I want to sort price column numerically with linq Lambdas.I have tried bellow.I am using Model values to filter query.
var query = ent.Product.Where(b => b.cp == Model.CodePostal);
if (Model.order_by_flg == 2)
{
query = query.OrderByDescending(a => a.price.PadLeft(10, '0'));
}
But it will not work and give me bellow error.
LINQ to Entities does not recognize the method 'System.String
PadLeft(Int32, Char)' method, and this method cannot be translated
into a store expression.
As it cant convert to Sql statement by Entity Framwork.
I also tried bellow.
var query = ent.Product.Where(b => b.cp == Model.CodePostal);
if (Model.order_by_flg == 2)
{
query = query.OrderByDescending(a => a.price.Length).ThenBy(a => a.price);
}
But i can't do this because it works for List but i cant first make list and then do this as i am using linq Skip() and Take() so first i have to sort it.
So how can i sort price column of type "VARCHAR" in Linq lambda?
EDIT
In table it is :
59,59,400,185,34
Wnen i use OrderBy.ThenBy it gives
34,59,59,106,185,400
It looks right as sorting ascending But when i use OrderByDescending.ThenBy it gives
106,185,400,34,59,59
So i can't use this.
NOTE: Please give reasons before Downvote so i can improve my question...
You can simulate fixed PadLeft in LINQ to Entities with the canonical function DbFunctions.Right like this
instead of this
a.price.PadLeft(10, '0')
use this
DbFunctions.Right("000000000" + a.price, 10)
I haven't tested it with MySql provider, but canonical functions defined in the DbFunctions are supposed to be supported by any provider.
It looks right as sorting ascending But when i use OrderByDescending.ThenBy it gives
106,185,400,34,59,59
That's because you're ordering by length descending, then value ascending.
What you need is simply to sort both by descending;
query = query.OrderByDescending(a => a.price.Length)
.ThenByDescending(a => a.price);
This should be faster than prepending numbers to sort, since you don't need to do multiple calculations per row but can instead sort by existing data.

Laravel query build based on relation

I have such query:
Tournament::has('participations', '<', '2')->get();
How can I replace constant number '2' on tournament's column named slots ?? I would like retrieve only these tournaments which have least participants than slots in tournament.
Let's start by using the column name instead of "2". Like you would do in "normal" SQL
Tournament::has('participations', '<', 'slots')->get();
Now, you don't even have to try that because it won't work. But why's that? Because Laravel treats slots like a string and escapes it so SQL does as well.
What you need to do, is use DB::raw(). raw makes sure Laravel changes nothing and just injects it into the SQL query
Tournament::has('participations', '<', DB::raw('slots'))->get();
Update
After some trying out I found this: (Its not very pretty but the only way I got it working)
$subquery = function($q) use ($uid){
$q->where('player_id', $uid);
}
Tournament::whereHas('participations', $subquery)
->whereHas('participations', $subquery, '<', DB::raw('slots'))
->get();
The first whereAs checks for count(*) > 0, the second count(*) < slots and the subquery filters by player id.

Laravel MySQL how to order results in the same order as in whereIn clause

I have two queries, the first one gives me an array of ids, that is in a specific order. Then that array of ids I pass it to the second query like so:
Operation::whereIn('id', $ids)->get();
But when I output the result of that query, the order has changed, if the array $ids was something like (4,2,6,9) which is the order I wanted the results to be in, the output will give me 2,4,6,9. How can I avoid that?
MySQL way of sorting with order same as in where in clause:
$ids; // array of ids
$placeholders = implode(',',array_fill(0, count($ids), '?')); // string for the query
Operation::whereIn('id', $ids)
->orderByRaw("field(id,{$placeholders})", $ids)->get();
You can do
$idsImploded = implode(',',$ids);
Operation::whereIn('id', $ids)->orderByRaw("FIND_IN_SET('id','$idsImploded')")->get();
It's a problem where MySql doesn't return the result in the order you specify them, so you need to reorder them after that.
A similar solution can be found here: avoid Sorting by the MYSQL IN Keyword
If you have the sorting order in 4,2,6,9, you can fetch these rows, then use php to sort.

MySQL using table columns in function to create alias to be used in sorting

It sounds more complicated than it actually is. Here is what I'm trying to do within the SELECT part:
SELECT TIMESTAMPADD(
UCASE(
SUBSTRING(offset_unit,1,CHAR_LENGTH(offset_unit)-1)
),1,'2003-01-02') as offset_date
offset_unit is a VARCHAR column in the database. It contains one of the following: "Hours","Minutes".
offset is an INT.
I am trying to convert the offset_unit to uppercase, after I have removed the last character ('s') so I can have a proper interval (MINUTE, HOUR...) so I can get a date that I can use in sorting afterwards, but MySQL keeps throwing an error. I have tested each step by adding one function at a time, and it only fails after I add TIMESTAMPADD. If I enter MINUTE manually then it works.
Any way to get this working?
Additional info: I am running this in CakePHP 1.3, in a find, within the 'fields' array, but that shouldn't be important.
this can be easily achived by using CASE WHEN clause as:
SELECT (CASE
WHEN offset_unit = 'HOURS'
THEN TIMESTAMPADD(HOUR,`offset`,'2003-01-02')
WHEN offset_unit = 'MINUTES'
THEN TIMESTAMPADD(MINUTE,`offset`,'2003-01-02')
END) AS offset_date
FROM my_table;
SEE SQLFIDDLE DEMO HERE
It doesn't work because TIMESTAMPADD does not take a string as the first argument, but a unit keyword, for example MINUTE. My guess is that you need to do this in two steps, first get the unit and then construct a query with the correct keyword.