Couchbase N1QL: GROUP BY CASE clause not working - couchbase

I am trying to execute GROUP BY CASE query on the Couchbase workbench.
The query is -
SELECT Hemisphere, COUNT(DISTINCT name) AS LandmarkCount
FROM `travel-sample` AS l
WHERE type="landmark"
GROUP BY CASE
WHEN l.geo.lon <0 THEN "West"
ELSE "East"
END AS Hemisphere;
This query is provided by the Couchbase documentation as an example to execute GROUP BY CASE queries on this link
I am getting the following error:
[
{
"code": 3000,
"msg": "syntax error - at AS",
"query_from_user": "SELECT Hemisphere, COUNT(DISTINCT name) AS LandmarkCount\r\nFROM `travel-sample` AS l\r\nWHERE type=\"landmark\"\r\nGROUP BY CASE\r\n WHEN l.geo.lon <0 THEN \"West\"\r\n ELSE \"East\"\r\nEND AS Hemisphere;"
}
]
I am working on Community Edition 6.0.0 build 1693.

I think I have the solution you want:
SELECT Hemisphere,
COUNT(DISTINCT name) AS LandmarkCount
FROM `travel-sample` AS l
LET Hemisphere = CASE
WHEN l.geo.lon <0 THEN "West"
ELSE "East"
END
WHERE type="landmark"
GROUP BY Hemisphere;
The error you're getting is because in 6.0, AS isn't supported in GROUP BY (as shown in the 6.0 docs and as the error message says).
An alternative is to use LET in 6.0+ to define a variable, as I did in the above example.
But note that LET is not required either; you could also write your query without it, like this:
SELECT CASE
WHEN l.geo.lon <0 THEN "West"
ELSE "East"
END AS Hemisphere,
COUNT(DISTINCT name) AS LandmarkCount
FROM `travel-sample` AS l
WHERE type="landmark"
GROUP BY CASE
WHEN l.geo.lon <0 THEN "West"
ELSE "East"
END;
But I think you'll agree that the former is easier to read, understand, and change.

Related

MySQL solution for using CASE WHEN with another CASE WHEN

I'm having troubles with the following query structure (I can't run it because I don't know how to do it).Simple form of it goes like this:
SELECT a,b,
CASE WHEN a=x AND b=y THEN "Something"
ELSE "Something Else"
END AS "1st Case",
CASE WHEN "1st Case"= "Something" THEN "Something New"
ELSE "Other"
END AS "2nd Case"
FROM table1
I thought of CTE but I can't use it with our server version. I thought of sub-query but don't know how to reference my custom column (result of "1st Case") in outer query.
Please help me with this, I guess, simple issue.
Try this:
select x.*, CASE WHEN 1stCase= 'Something' THEN 'Something New'
ELSE 'Other'
END AS '2nd Case' from
(SELECT a,b,
CASE WHEN a=x AND b=y THEN 'Something'
ELSE 'Something Else'
END AS 1stCase from table1)x

Combine 2 CASE statements inside SELECT - MySQL

i am using this sql block right now
SELECT mail_id,
CASE consignor
WHEN 'aby' THEN
'con'
ELSE
'rec'
END AS type,
CASE consignor
WHEN 'aby' THEN
recipient
ELSE
consignor
END AS other,
mail, mail_time
FROM mail m
WHERE m.consignor = user OR m.recipient = user
ORDER BY mail_time DESC
As you can see 2 case statements does exactly same job here so i thought i somehow can combine them. However my attemps did not yield any results. Anyone knows something better here?
What i've tried?
SELECT mail_id,
CASE consignor
WHEN 'aby' THEN
'con', recipient
ELSE
'rec', consignor
END AS ( type, other ),
mail, mail_time
FROM mail m
WHERE m.consignor = user OR m.recipient = user
ORDER BY mail_time DESC

Group By Issue converting MySQL to PostgreSQL

I am trying to convert an old symfony 1.4 app from MySQL to PostgreSQL.
I keep running into the same issue over and over again.
I have some long joins and it is always complaining about having to have a Group By... and in some cases I add the Group By and it asks for another one.
I am new to postgres and I have absolutely no idea what is going on.
Here are the doctrine queries and error messages.
public function getClassifieds($gs_id, $sort_param, $sorter) {
$q = Doctrine_Query::create()
->select('a.*, u.*, t.*,ug.*,ur.*, avg(ur.rating) as rating ')
->from('Items a')
->leftJoin('a.MonitoredAds ma ON ma.item_id = a.id')
->leftJoin('a.GameCategories gc ON gc.game_id = a.game_id')
->leftJoin('a.User u ON u.id = a.user_id')
->leftJoin('u.Profile ug ON ug.user_id = u.id')
->leftJoin('a.UserRatings ur ON ug.user_id = ur.seller_id')
->where('a.game_server_id = ?', $gs_id)
->andWhere('a.quantity > ?', 0);
switch ($sorter) {
case 'datetime_oldest_to_newist':
$q->orderBy('a.created_at asc');
break;
case 'datetime_newest_to_oldest':
$q->orderBy('a.created_at desc');
break;
case 'price_lowest_to_highest':
$q->orderBy('a.price + 0 ASC');
break;
case 'price_highest_to_lowest':
$q->orderBy('a.price + 0 DESC');
break;
case 'quantity_lowest_to_highest';
$q->orderBy('a.quantity asc');
break;
case 'quantity_highest_to_lowest';
$q->orderBy('a.quantity desc');
break;
case 'quantity_highest_to_lowest';
$q->orderBy('a.quantity desc');
break;
case 'sortby_usernameasc':
$q->orderBy('u.username asc');
break;
case 'sortby_usernamedesc':
$q->orderBy('u.username desc');
break;
case 'sortby_userstatus':
$q->orderBy('ug.user_status asc');
break;
}
return $q;
}
Gives Me this error message
SQLSTATE[42803]: Grouping error: 7 ERROR: column "i.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT i.id AS i__id, i.featured AS i__featured, i.status AS...
So I change the code to ...
->andWhere('a.quantity > ?', 0)
->groupBy('a.id');
Then I get a new error...
SQLSTATE[42803]: Grouping error: 7 ERROR: column "s.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ... AS i__created_at, i.updated_at AS i__updated_at, s.id AS s_...
I stopped here because this is changing the behaviour of the query in a major way and I really don't know what's going on.
I am not afraid of reading the docs but I don't even know where to start.
If you know what the issue could be please let me know. If you know where I should be looking in the docs please let me know that as well.
Thank you in advance.
Scott
It is not correct for PostgreSQL without GROUP BY all columns besides ur.rating:
->select('a.*, u.*, t.*,ug.*,ur.*, avg(ur.rating) as rating ')
Every selected and ordered column must be in GROUP BY or in agregate function.
For example, rewrite query:
->select('u.id, avg(ur.rating) as rating ')
...
->orderBy('u.id');
->groupBy('u.id');

incorrect syntax near the keyword 'in' in case statement

Here is the query
`select
p.occid,
p.occdate,
f.fillername,
badgeID= null,
p.mc
p.mctime,
problemcode = isnull(p.problemcode,400),
pc.problemdesc,
p.timerresolved,
p.duration,
e.employeename,
pl.durationinminutes,
pl.timein,
pl.timeout,
problemdescription = datediff(minute,occdate,timeresolved)
from problem as p
left join filler as f
on p.fillerid = f.fillerid
left join problemlog as pl
on p.occid = pl.occid
left join problemcode as pc
on p.problemcode = pc.problemcode
left join employee as e
on pl.badgeid = e.id
where f.intials = #fillerselect and
occdate between dateadd(day, datediff(day, '19000101', #startdate),
cast(#starttime as datetime2(7))) and
dateadd(day, datediff(day, '19000101', cast #endtime as datetime2(7)))
and p.problemcode in (#problemcode)
and #Duration <= datediff(minute, occdate, timeresolved)
and case when #reportparameter like 'false'
then e.employeename in (#employee)`
My issue is in the case clause. I get an error stating "incorrect syntax near the keyword 'in'. Does anyone have any ideas how to overcome this?
I should have mentioned that #employee can have multiple selections. When #reportparameter is 'False', then #employee is 'None', stating we are not filtering by employee. When #reportparameter is 'true', we are filtering by employee and #employee may or may not have multiple selections.
I think, your 2 last lines (and case when then) should be something like this:
and ( #reportparameter like 'false' and e.employeename in (#employee) )
It looks like you want to conditionally check e.employeename against #employee when the #reportparameter = 'false'
I wouldn't recommend using a case statement for this action. Rather just use an OR condition. The SQL Server Optimizer will process the OR faster than a CASE statement within the WHERE clause (in general.)
WHERE f.intials = #fillerselect
AND occdate BETWEEN dateadd(DAY, datediff(DAY, '19000101', #startdate), cast(#starttime AS datetime2(7))) AND dateadd(DAY, datediff(DAY, '19000101', CAST #endtime AS datetime2(7)))
AND p.problemcode IN (#problemcode)
AND #Duration <= datediff(MINUTE, occdate, timeresolved)
AND ((#reportparameter = 'false'
AND e.employeename IN (#employee))
OR (#reportparameter <> 'false'
AND e.employeename IN (#somethingelse)))
There look to be other things you may want to change in your WHERE clause as well. I'm not 100% sure you're using the IN condition appropriately. If #employee only contains one employee, you should be using = instead of IN. I'm assuming #ReportParameter is a string variable but using 'false' as a value is unusual. Ususally you would use a BIT and check against 1 or 0 for True vs. False.
i think your second dateadd function is in complete
dateadd(day, datediff(day, '19000101', cast #endtime as datetime2(7)))
here i can see only 2 parameters, i think 3rd one is missing, adding 3rd parameter may resolve issue

Using comparison as alias in select for Doctrine2

Trying to do this in Doctrine2:
...->createQuery('SELECT m.id, (m.status != 1) as verified...
But that throws an error - if I take parenthesis off I get another error. How do I achieve this m.status comparison?
Thanks
Doctrine 2 doesn't support these comparisons in the SELECT clause (at least not up to 2.3, not sure about 2.4).
You can use a CASE expression as workaround:
SELECT m.id, CASE WHEN m.status != 1 THEN 1 ELSE 0 END AS verified ...
or:
SELECT m.id, CASE WHEN m.status = 1 THEN 0 ELSE 1 END AS verified ...
If you need verified for an ORDER BY clause (or something like that), but don't actually need it in the result, you can use the HIDDEN expression:
SELECT m.id, CASE WHEN m.status = 1 THEN 0 ELSE 1 END AS HIDDEN verified ...
A completely different solution is to write a custom DQL function.
You can use the solution proposed here: Cumulative DQL with Doctrine
When working with entities, keep in mind that adding selects will make the query return an array for each result:
$res = $em->createQueryBuilder()
->from('BlogPost', 'p')
->select('p')
->addSelect('(2+3) AS dummy')
->getQuery()->getResult();
Iterating over $res will return an array:
foreach($res as $mixed){
echo get_class($mixed[0]); //$mixed[0] contains the BlogPost
echo $mixed['dummy']; //displays the dummy result (5)
}
check this out: 13.2.4. Using Expr* classes to create conditionals
using Expression methods you could do something like:
$qb = $this->entityManager->createQueryBuilder();
$query = $qb->select('m.id')
->from('Entities\MyEntity', 'm')
/*neq() is the "not equal" comparison function*/
->where($qb->expr()->neq('m.status', $someValue)),
->getQuery();