I'm using Symfony Project 1.4 and Postgresql
I got error query in doctrine using
$q = Doctrine_Query::create()
->select("count(sex) as total, sex")
->from('Biodata')
->groupBy('sex')
->execute();
there is always display error like this when debug:
SQLSTATE[42803]: Grouping error: 7 ERROR: column "e.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT e.id AS e__id, e.sex AS e__sex, COUNT(e.sex) AS e__0 ...
^. Failing Query: "SELECT e.id AS e__id, e.sex AS e__sex, COUNT(e.sex) AS e__0 FROM biodata e GROUP BY e.sex"
How to fix it and hide e.id column, is this bugs or need a trick?
Excepted result:
Doctrine automatically add the primary key to the select list. We've got the same error using MSSQL.
Try to add not hydrate result:
$q = Doctrine_Query::create()
->setHydrationMode(Doctrine_Core::HYDRATE_NONE)
->select("count(sex) as total, sex")
->from('Biodata')
->groupBy('sex')
->execute();
You won't have column name, but something like this I think:
+========+=========+
| 0 | 1 |
+========+=========+
| 183 | 1 |
+--------+---------+
| 54 | 2 |
+========+=========+
Related
The question has been resolved. But if you have a "better" or another way to do it then feel free to add a comment! Thanks all for reading! :)
I'm trying to make a dynamic query. Everything is working perfectly except for one thing. I've Google'd for days but I can't figure out how I can make the following work;
SELECT project.name, project.description, track.name, track.description
, SDG.position, SDG.title, SDG.description
, sprint_numbers.number, sprint_options.option
, resources.name, resources.description
, URLs.URL
FROM project INNER JOIN track ON project.track_id = track.id
INNER JOIN project_SDG ON project.id = project_SDG.project_id
INNER JOIN SDG ON project_SDG.SDG_id = SDG.id
INNER JOIN sprint ON sprint.project_id = project.id
INNER JOIN sprint_numbers ON sprint_numbers.id = sprint.sprint_number_id
INNER JOIN sprint_options ON sprint_options.id = sprint.sprint_option_id
INNER JOIN resources ON project.id = resources.project_id
INNER JOIN URLs ON URLs.id = resources.id
WHERE 1=1
AND MATCH (project.name) AGAINST (:name_project)
AND MATCH (project.description) AGAINST (:description_project)
AND SDG.id = :SDG_1
AND SDG.id = :SDG_2
The query executes but does not return anything. The problem is that the SDG.id can't be true to both :SDG_1 and :SDG_2.
Using the OR operator works, but that does not return it the way I want. It must "act" as an AND operator. (:SDG_1 & :SDG_2 are the names of the PHP variables that bind to the SQL statement parameters.)
The query should filter for both values. The values given to :SDG_1 and :SDG_2 must both exist in the SDG.id column of the project_SDG table. If the value of :SDG_1 exists, but :SDG_2 not, then the query should not return anything.
I found this on StackOverflow but it did not work for me: SELECTING with multiple WHERE conditions on same column
I hope someone can help me out.
EDIT: minimal reproducible example
QUERY:
SELECT * FROM project
INNER JOIN project_SDG ON project.id = project_SDG.project_id
INNER JOIN SDG ON project_SDG.SDG_id = SDG.id
WHERE SDG.id = 1 AND SDG.id = 7 AND SDG.id = 14 AND SDG.id = 17
Project table
+------------------+---------------------------+------------+
| id name | description | track_id |
+------------------+---------------------------+------------+
| 1 project name | This is a description 2 | |
+------------------+---------------------------+------------+
SDG table
+-----+-----------+-------------+---------------------------------------------+
| id | position | title | description |
+-----+-----------+-------------+---------------------------------------------+
| 1 | 1 | SDG 1 to 17 | There're multiple SDGs ranging from 1 to 17 |
| 17 | 17 | SDG 1 to 17 | There're multiple SDGs ranging from 1 to 17 |
+-----+-----------+-------------+---------------------------------------------+
project.SDG (bridge-table)
+------------+--------+
| project.id | SDG.id |
+------------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
+------------+--------+
You want for each project.id both values :SDG_1 and :SDG_2 to exist for SDG.id, so use this in the WHERE clause:
WHERE 1=1
AND MATCH (project.name) AGAINST (:name_project)
AND MATCH (project.description) AGAINST (:description_project)
AND project.id IN (
SELECT project_id
FROM project_SDG
WHERE SDG_id IN (:SDG_1, :SDG_2)
GROUP BY project_id
HAVING COUNT(DISTINCT SDG_id) = 2
)
Could you provide a minimal reproducible example for your query?
Generally speaking, one field cannot be equal to two different values in the same time. So, you have either mixed up the logical operators or you need two different fields.
I can assume that in your case there may be several related records with different values. In this case, you need to join the same table twice with different aliases. Let's say as SDG1 and SDG2. After that you can compare
... `SDG1`.id = :SDG_1 AND `SDG2`.id = :SDG_2
Update:
The win trick is groupping. You can enumerate all required SDG IDs and count how many of them is in group. Just for example in case of two IDs:
SELECT project.id
FROM project
JOIN project_SDG ON project_SDG.project_id = project.id
JOIN SDG ON SDG.id = project_SDG.SDG_id
WHERE SDG.id IN(1,2)
GROUP BY project.id
HAVING COUNT(*) = 2
See my sandbox here: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/0
If you need all project's fields, you have to put this into sub-query as
... WHERE id IN ( subquery here )
Subquery example: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/1
I have already answered here, but I have another approch.
1. Find bunch of IDs assotiated with some project
To find project IDs we can test lonely pivot table without any join:
SELECT project_id FROM project_SDG
WHERE SDG_id IN(1,2,6)
GROUP BY project_id HAVING COUNT(*) = 3
it gives us list of Project IDs
2. Access all project fields and add extra conditions
SELECT project.*
FROM project
JOIN (
SELECT project_id FROM project_SDG
WHERE SDG_id IN(1,2,6)
GROUP BY project_id HAVING COUNT(*) = 3
) AS ids ON ids.project_id = project.id
WHERE
MATCH(project.name) AGAINST ('project') AND
MATCH(project.description) AGAINST ('sit')
you can play with it here: https://www.db-fiddle.com/f/pixe3Zcs75Mq2PyCYPk913/3
3. Prepare query on the PHP side
I will use known technique to prepare SQL statement.
$ids = [1, 2, 6]; // it can come from request parameters
$text1 = 'project';
$text2 = 'sit';
// build ?,?,?,... pattern
$qmarks = implode(',', array_fill(0, count($ids), '?'));
// Use SQL query above
$sth = $dbh->prepare("
SELECT project.*
FROM project
JOIN (
SELECT project_id FROM project_SDG
WHERE SDG_id IN({$qmarks})
GROUP BY project_id HAVING COUNT(*) = ?
) AS ids ON ids.project_id = project.id
WHERE
MATCH(project.name) AGAINST (?) AND
MATCH(project.description) AGAINST (?)
");
$sth->execute(array_merge($ids, [count($ids), $text1, $text2]));
$records = $sth->fetchAll();
I am trying to get how many names do I have in database. For this purpose I am using Query Builder like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->count();
Is says that 24, which is not correct, because if I will write code like this:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
result object contains 247 elements, which is correct. I have tried to play with skip/take, but still no results. Where am I wrong? Thanks for any help.
I think it's the other way around, you're not getting 24 groups. You're getting 24 elements within the first group. That configuration results in the following query:
SELECT
COUNT(*) AS 'aggregate',
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`;
What you end up with will look something like this:
+---------------+---------+
| aggregate | name_id |
+---------------+---------+
| 24 | 1 |
+---------------+---------+
| 5 | 2 |
+---------------+---------+
| 30 | 3 |
+---------------+---------+
| ... and so on | 4 |
+---------------+---------+
Query\Builder just doesn't realize you can get more than one result back when count() is involved.
You were pretty close to the right answer yourself though.
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get();
get() returns an Eloquent\Collection, child of Support\Collection, which has its own version of the count method. So your answer is just:
$namesIdsCount = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having)
->get()
->count();
If you really want this to happen in MySQL, the query you want to happen would look like this:
SELECT COUNT(*) FROM (
SELECT
`name_id`
FROM `names_to_options`
WHERE EXISTS(
{your $havingRaw sub-query}
)
GROUP BY `name_id`
) AS temp;
For that, you can do this:
$query = DB::table('names_to_options')
->select('name_id')
->groupBy('name_id')
->havingRaw($having);
$sql = $query->toSql();
$values = $query->getBindings();
$count = DB::table(DB::raw('('.$sql.') AS `temp`'))
->selectRaw("COUNT(*) AS 'aggregate'", $values)
->first()
->aggregate;
MySQL performance can get a little hairy when asking it to write temp-tables like that though, so you'll have to experiment to see which option is faster.
Inuyaki is right
(id, name_id),
(1,1),
(2,1),
(3,2),
(4,3)
There are are four rows so get() method will return 4 rows
but there are three groups if you use groupBy [name_id]
1 (1,1)
2 (2)
3 (3)
now count will return 3
hope this will help.
I am using Laravel 5.4's Query Builder to perform a series of leftJoins on three tables. Here are my tables:
items
id type title visibility status created_at
-- ---- ----- ---------- ------ ----------
1 1 This is a Title 1 1 2017-06-20 06:39:20
2 1 Here's Another Item 1 1 2017-06-24 18:12:13
3 1 A Third Item 1 1 2017-06-26 10:10:34
count_loves
id items_id user_id
-- ------- -------
1 1 2
2 1 57
3 1 18
count_downloads
id items_id user_id
-- ------- -------
1 1 879
2 1 323
And here is the code I am running in Laravel:
$items_output = DB::table('items')
->leftJoin('count_loves', 'items.id', '=', 'count_loves.items_id')
->leftJoin('count_downloads', 'items.id', '=', 'count_downloads.items_id')
->where('items.visibility', '=', '1')
->where('items.status', '=', '1')
->orderBy('items.created_at', 'desc')
->select('items.*', DB::raw('count(count_loves.id) as loveCount'), DB::raw('count(count_downloads.id) as downloadCount'))
->groupBy('items.id')
->get();
When I return the results for this query, I am getting the following counts:
count_loves: 6
count_downloads: 6
As you can see, the actual count values should be:
count_loves: 3
count_downloads: 2
If I add another entry to the count_loves table, as an example, the totals move to 8. If I add another entry to the count_downloads table after that, the totals jump to 12. So, the two counts are multiplying together.
If I die and dump the query, here's what I get:
"query" => "select 'items'.*, count(count_loves.id) as loveCount,
count(count_downloads.id) as downloadCount from 'items' left join
'count_loves' on 'items'.'id' = 'count_loves'.'items_id' left join
'count_downloads' on 'items'.'id' = 'count_downloads'.'items_id'
where 'items'.'visibility' = ? and 'items'.'status' = ? group by
'items'.'id' order by 'items'.'created_at' desc"
How do I perform multiple leftJoins using Query Builder and count on several tables to return the proper sums?
NOTE:
This is intended as a HELP answer not the total absolute answer but I could not write the code in a comment. I am not asking for votes (for those who just can't wait to downvote me). I have created your tables and tried a UNION query on raw sql. I got correct results. I dont have laravel installed, but maybe you could try a UNION query in Laravel.
https://laravel.com/docs/5.4/queries#unions
select count(count_downloads.user_id)
from count_downloads
join items
on items.id = count_downloads.items_id
UNION
select count(count_loves.user_id)
from count_loves
join items
on items.id = count_loves.items_id
maybe someone can help me.
I have 2 sql tables:
// groups
| id_group | namegroup |
+------------+-----------+
| 30 | s |
// contacts
| name | group |
+------+-------+
| juan | s |
I need to DELETE a group from ID, but no has contacts associated with it.
I test the following query but doesnt work.
DELETE
FROM group
WHERE id_group = 30
AND (
SELECT
count(*) AS id
FROM contacts co
INNER JOIN GROUP c ON co. GROUP = c.namegroup
WHERE c.id_group = 30
) = 0
Thanks
You can try the following query if you want to delete group having ID = 30 only if the group is not associated to any contact :
Query #1:
DELETE
`groups`
FROM `groups`
LEFT JOIN contacts
ON contacts.`group` = `groups`.namegroup
WHERE `groups`.id_group = 30
AND contacts.`group` IS NULL;
And if you want to delete all groups which don't have any associated contact then try the following query instead:
Query #2:
DELETE
`groups`
FROM `groups`
LEFT JOIN contacts
ON contacts.`group` = `groups`.namegroup
WHERE contacts.`group` IS NULL;
If you define firigen key mysql will handle this issue and you do not need to do anything
In these cases(without forigen key) i usually first run following query:
select count(*) as id from contacts co inner join group c on co.group=c.namegroup where c.id_group=30
And say to user which if they can delete or not and if he could delete that row:
delete from group where id_group=30
I tried to find a solution like query which you had but could not and suggest this solution for you.
So I got a table called matches containing 2 teams ID, and these teams are in the same table called clans
matches
team1_id | team2_id
2 | 4
1 | 2
4 | 1
and
Clans
ID | Name
2 | abc
1 | cde
4 | efg
My goal is that when I print this out at the webpage, it shows the teams names instead of their IDs. Now to explain it simple, I'm using laravel, with the following code:
$unfinished = DB::table('matches')->where('team1_score', NULL)
->join('matches', 'matches.team1_id', '=', 'clans.id')
->join('matches', 'matches.team2_id', '=', 'clans.id')
->select('clans.clan_name as team1_name', 'clan_name as team2_name', 'matches.id'
)->get();
and I need it all stored in $unfinished. Naturally, this code does'nt work, and I think I understand why. What i just can't figure out however, is how to solve this so that it will work. It spits out the following exakt error:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'matches' (SQL: select clans.clan_name as team1_name, clan_name as team2_name, matches.id, tournaments.name from matches inner join tournaments on tournaments.id = matches.tournaments_id inner join matches on matches.team1_id = clans.id inner join matches on matches.team2_id = clans.id where team1_score is null)
Use aliases:
$unfinished = DB::table('matches')->where('team1_score', NULL)
->join('clans AS clans1', 'matches.team1_id', '=', 'clans1.id')
->join('clans AS clans2', 'matches.team2_id', '=', 'clans2.id')
->select('clans1.clan_name as team1_name', 'clans2.clan_name as team2_name', 'matches.id'
)->get();