Why group by is not working properly? laravel - php

I'm currently using groupBy to group concatenated (book name and book_author). I'm intentionally using groupBy because I have other columns to get their average, and sum.
I initially used this code below. But it returning me an error.
Illuminate\Database\QueryException: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated
Reference::select('*')
->selectRaw("CONCAT(book_name, ' ', book_author) AS book")
->groupBy('type');
If I add an id column inside groupBy, it does not returning an error. But it does not order, I still getting duplicate book.
Reference::select('*')
->selectRaw("CONCAT(book_name, ' ', book_author) AS book")
->groupBy(['id', 'type']);
Someone, how to achieve this properly?

TLDR; When you use group by in strict mode, your selected fields must be aggregated fields.
Let's say you have two books with the same type.
book_name
book_name
type
First
author
1
Second
editor
1
When you group by type, those having the same type will be merged into one. So wich result will it be for CONCAT(book_name, ' ', book_author) ?
First author ?
Second editor ?
First editor ?
Second author?
The query doesnt gamble when strict mode is active, you need to aggregate the fields, for example LISTAGG(book_name , ',') is an aggregationg of the field book_name and result in 'first,second'.
If you disable the strict mode ('strict' => false,) in the file config/database.php, the result might be any of the 4 listed above as it is kinda random.
Other example for aggregation functions: SUM(), AVG(), COUNT()...

Please use the below link, as the solution is already available.
Solution Link.
Please check and you will find the solution.

Related

MySQL query gives empty result when searching for word "other"

The following query gives no results, but it works with every other word (e.g. +blue). Is other a reserved word? If so, I can't find this in any documentation. I'm using MySQL 5.6 and PHP 7.3. By the way, I used to have a FULLTEXT index the style column that contains the "other" tag, but I removed it to troubleshoot this issue. It has made no difference.
SELECT * FROM products_master WHERE MATCH(category, subcategory, title, period, color, style, brand, more_tags) AGAINST('+other' IN BOOLEAN MODE) AND qty <> '0' AND replacement = '' ORDER BY id DESC
Update: I found that +none also gives no results, but +empty works fine.
Any ideas?

How to separate SQL column data separated by comma to individual values and then count these values

Am using a SQL command in PHP to count the no of values inserted in a column named attack_type. I want to count the occurrence of individual values like website defacement in the whole column of the table. But here the column attack_type contain different values, separated by a comma and the count is treating whole column data as a string. Below is my current SQL statement with its output
I tried explode print_r in PHP
SELECT attack_type,
count(*) as number
FROM data_input_test
GROUP BY attack_type
Here is the output of the above statement
generated:
https://drive.google.com/open?id=1TyRL_Mh0OOJWaCpFczxmBr34No9LUpzH
But what I want is :
https://drive.google.com/open?id=1eeA_1TCER0WMpZwSkBDMzRtRa8xihbZd
and so on. The above desired output is edited to show what I exactly want.
Other answer on stackoverflow and on other forums are either irrelevant or are using regrex or a new table creation in one or the other way. That I don't want as my hosting has some limitations. My hosting doesnt provide creation of triggers, regrex or creation of temp tables
I may have a solution for this but don't know how to apply here. Possible here: https://www.periscopedata.com/blog/splitting-comma-separated-values-in-mysql
Please someone explain me how to apply the same here.
So I finally worked around to get my work done using the select only. This only works if you have a finite set of data or specifically less than 64 values.
Change your column datatype to 'set' type. And enter your set values.
Now use select, count, find_in_set and union functions of sql.
Example:
union select 'Un-patched Vulnerable Software Exploitaion'as type, count(*) as number from data_input_test where find_in_set('Un-patched Vulnerable Software Exploitaion',attack_type)```
and so on for all your values
I know this is not how you should do but as the legends say this works 😎😎
If you just want to count comma-separated values in rows, you can use:
SELECT SUM(LENGTH(attack_type) - LENGTH(replace(attack_type, ',', '')) +1) AS TotalCount
FROM table_name;

Laravel Group & Count by Eloquent Relationship

I know this question has be asked before here: Laravel Grouping by Eloquent Relationship but the answers are from 2016 and they seem not to work in 2019. Also my question is more simple, since I only need one relation level.
My Question
A
user has multiple items.
How to find how many items a user has of each item_type with one query?
This is what I tried:
A query like
User::with(['items' => function($q){
$q->groupBy('type');
});
returns this error:
Syntax error or access violation: 1055 Expression #1 of SELECT list
is not in GROUP BY clause and contains nonaggregated column 'items.id'
which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by
I tried to fix this error with the following query:
User::with(['items' => function($q){
$q->select('type', \DB::raw('count(*) as total'))
->groupBy('type');
});
However, this returns a collection of users where each user's item collection is empty.
Is it somehow possible to group by a relation in the query?
There is an error :
You are using $q as closure argument and inside you are using $query. Also sometimes I have faced issue where I had to pass the foreign key inside the relation query closure to get the results :
<?php
$userWithItems = User::with(['items' => function($q){
$q->select('type', \DB::raw('count(*) as total'), 'user_id')
->groupBy('type');
});
Try it once by removing user_id if it works then it's better. Secondly you can not select non aggregated columns in mysql when you have groupby. The option is disable only_full_group_by in mysql configurations. So mostl likely user_id will also fail unless you disable this configuration

Understanding COUNT() as `count`

I'm currently learning how to build a site in PHP MySQL. However, I seem to fail to understand COUNT() as count and wouldn't mind some further explanation.
I get the principles of COUNT, 0 || 1, and how it returns all the values that pertain to that query.
But, don't see how COUNT as count works. Anyhow, this is how the code I'm writing goes - so we have a working example - and where I first became perplexed.
"SELECT COUNT(id) as count, id
FROM user
WHERE email='$email' AND password='".md5$password."'"
That is what is called alias which is sometimes used to show a more appealing column header to users or the calling code
SELECT COUNT(`id`) as `count`....
will print
count
--------
5
The alias standing as the column header instead of any arbitrary string: See the SQLFiddle to see the difference
From the fiddle you can see that the header column looks somehow e.g.
count(*)
--------
5
With Count() you can count the returning rows of a result set. The also the official MySQL documentation about count:
Databases are often used to answer the question, “How often does a certain type of data occur in a table?” For example, you might want to know how many pets you have, or how many pets each owner has, or you might want to perform various kinds of census operations on your animals.
Counting the total number of animals you have is the same question as “How many rows are in the pet table?” because there is one record per pet. COUNT(*) counts the number of rows, so the query to count your animals looks like this:
SELECT COUNT(*) FROM pet;
The part with AS count means that this colum will get a name which you can use e.g. in PHP. See also this explenation on w3schools:
You can give a table or a column another name by using an alias. This can be a good thing to do if you have very long or complex table names or column names.
An alias name could be anything, but usually it is short.
as count is just an alias. You can use as for any field or method selected. it means you change the name of the column being returned in your dataset.
SELECT `field` as another_name
So:
SELECT COUNT(*) as `count`
Just renames the column from COUNT(*) to count making it easier to work with whereever you are maniuplating your result set.
It also makes for easier access within your current query. Many would do the following with large table names:
SELECT * FROM `table_with_ridiculous_name` as twrn WHERE twrn.id = 1
If you ran this sql:
SELECT COUNT(id), id ....
You would get (after doing a *_fetch_assoc) $row['numberofrecordshere'] which would be very hard to echo (or use in a comparison) unless you knew how many records there would be (which would defeat the purpose of this result, anyway)
Returning it as count allows you to get to it in the resulting array by using $row['count']

Little explanation of this mysql code

I got this answer from somebody on another Q before, but I would like to get an explanation of this, so that I fully understand the problem.
I have a table, with a column which contains a value of either "private" or "company".
Thing is, I want to check how many "private" and "company" values are in my records, so that I can display them with the search results later on.
So if there are 4 company ads, and 1 private ad, this is the results:
Company = 4
Private = 1
All ads = 5
And here is the code I got from someone about how to do this, in other words, this is what I would like explained:
SELECT
IFNULL( field , 'All ads' ) AS 'Type',
COUNT( * )
FROM
`table`
GROUP BY
field
WITH ROLLUP
Thanks
I assume that the part you don't understand is the ROLLUP clause, which is not often used.
The manual describes it well, but the basic idea is that each group is aggregated, and then you get one extra group at the end which aggregates the rows from all groups, and where Field is set to NULL.
The IFNULL expression changes the NULL to a readable string instead. You could use COALESCE instead of IFNULL to get the same effect.
Select the Type field, and if the value is null, use All Ads as the default value.
Select them from the table, and group them by field.
As far as I can tell, this will count each the number of entries of each 'Type', and all the entries that have a null value will simply go under the 'All Ads' count.
Just BTW, if you look at the IFNULL() function, it is pretty easy to figure out. It clearly states IF NULL, so it is checking if something is null. Then you pass it a field name and a static value. Kind of makes sense that it is checking if that field value is false. And the only other thing there is the value, so we can come to the conclusion that it will use the static value, if the field value is null.
Selects all adverts from the table "table", it groups them by field, this means that all the ads that are "public" are placed into a group "public" with an associated number. So if you have 10 public adverts they're all grouped into "public adverts" with the value 10.
Does this make sense?

Categories