I am using Cognos embedded in Watson Studio and attempted creating the following calculation with case statement (both month_3 and avg2m are measures).
Cognos reports XQE-V5-0017 V5 syntax error found for data item 'calculation-new' of query 'validateQuery', invalid token "<" found after "case (( allin_shaped_csv.month_3 - avg2m ) / avg2m ) when ".
May you help fixing the syntax error?
case (( allin_shaped_csv.month_3 - avg2m ) / avg2m )
when <-0.50 then -100;
when <-0.20 then -50;
when <0 then -20;
when 0 then 0;
when >0 then 20;
when >0.50 then 50;
when >0.99 then 100;
end case;
it looks it works this way :
case
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<-0.50 then -100
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<-0.20 then -50
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )<0 then -20
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )=0 then 0
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0 then 20
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0.50 then 50
when (( allin_shaped_csv.month_3 - avg2m ) / avg2m )>0.99 then 100
else 0
end
Related
This is my code:
cohort_query <- dbGetQuery(con,'select u.unique_id customer_id,
o.user_id user_hash,
"min"(o.deliveryconfirmeddate) first_order,
(
CASE
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'1\' YEAR)
) THEN 0
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'2\' YEAR)
) THEN 1
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'3\' YEAR)
) THEN 2
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'4\' YEAR)
) THEN 3
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'5\' YEAR)
) THEN 4
ELSE 5
END
) "cohort_year",
min(o.id) as first_order_id
FROM (
"bj-analytics"."mysql_bj_orders" o
INNER JOIN "bj-analytics"."mysql_bj_users" u ON (u.user_id = o.user_id)
)
WHERE (
(
(o.connectedorder = false)
AND (o.status <> \'cancelled\')
)
AND (o.status <> \'Cancelled\')
)
GROUP BY 1,
2
HAVING (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'6\' YEAR)
)
and "min"(o.deliveryconfirmeddate) < date(\'2021-11-01\')')
This all runs fine. Basically, I want to make the 2021-11-01 date a variable, so that I only have to enter it once.
Someone recommended glue_sql but I couldn't make it work. I think it's an issue with the double quotation marks and the single marks. I tried to change these to all "" or to all '' but then the query just doesn't run!
I also found that I have to include \'s - again without them doesn't seem to run.
I'm new to R so not too sure how to get around this!
Basically can anyone please help with turning that date into a variable?
Any help is much appreciated - thanks!
Never use paste or sprintf to put "data" into a query, for many reasons (query optimization/caching and accidental sql-injection being the top two), instead use parameter-binding:
DBI::dbGetQuery(con, "
select (case
when (5 < ?) then 5
when (3 < ?) then 3
when (1 < ?) then 1
else 0 end) as quux",
params = replicate(n=3, expr=3, simplify = FALSE))
# quux
# 1 1
DBI::dbGetQuery(con, "
select (case
when (5 < ?) then 5
when (3 < ?) then 3
when (1 < ?) then 1
else 0 end) as quux",
params = replicate(n=3, expr=10, simplify = FALSE))
# quux
# 1 5
The replicate(3,10,F) is just a programmatic way to do list(10,10,10), they are equivalent here. My use of static comparisons (5 < ?) is solely for placeholders, your min(.) should work fine.
(FYI, one more benefit of parameter-binding: no need to deal with additional quotes in the query.)
See https://db.rstudio.com/best-practices/run-queries-safely/#parameterized-queries for more discussions on safely using data in the query.
I think that would make your query this:
cohort_query <- dbGetQuery(con, 'select u.unique_id customer_id,
o.user_id user_hash,
"min"(o.deliveryconfirmeddate) first_order,
(
CASE
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'1\' YEAR)
) THEN 0
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'2\' YEAR)
) THEN 1
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'3\' YEAR)
) THEN 2
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'4\' YEAR)
) THEN 3
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'5\' YEAR)
) THEN 4
ELSE 5
END
) "cohort_year",
min(o.id) as first_order_id
FROM (
"bj-analytics"."mysql_bj_orders" o
INNER JOIN "bj-analytics"."mysql_bj_users" u ON (u.user_id = o.user_id)
)
WHERE (
(
(o.connectedorder = false)
AND (o.status <> \'cancelled\')
)
AND (o.status <> \'Cancelled\')
)
GROUP BY 1,
2
HAVING (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'6\' YEAR)
)
and "min"(o.deliveryconfirmeddate) < date(?)'),
params = replicate(n=7, expr='2021-11-01', simplify=FALSE)
Is it practically possible to create a triangle of stars like this as below in PL/SQL. I know that this could be done easily in any other programming language like C,C++,Java but want to know whether it is really possible with just SQL or PL/SQL. This is for my homework and I should use conditional clauses (IF THEN ELSE), loops(FOR, WHILE).
*
***
*****
*******
*********
***********
*************
and
*****
***
*
Try this.
The first loop will print the stars in triangle and the second loop will reverse it.
In PL/SQL:
BEGIN
FOR i IN 1 .. :p
LOOP
DBMS_OUTPUT.put_line (LPAD (LPAD ('*', i, '*'), :p + 1, ' '));
END LOOP;
FOR i IN 1 .. :p
LOOP
DBMS_OUTPUT.put_line (LPAD (LPAD ('*', :p-i, '*'), :p + 1, ' '));
END LOOP;
END;
In SQL:
SELECT LPAD (LPAD ('*', level, '*'), :p + 1, ' ') a
FROM DUAL
CONNECT BY LEVEL <= :p;
This can be done purely in sql (in Oracle), like so:
SELECT RPAD(' ', :p_num_triangle_rows - LEVEL) || RPAD('*', LEVEL * 2 -1, '*') || RPAD(' ', :p_num_triangle_rows - LEVEL) triangle
FROM dual
CONNECT BY LEVEL <= :p_num_triangle_rows
ORDER BY CASE WHEN :p_ascending_or_descending = 'a' THEN LEVEL END ASC,
CASE WHEN :p_ascending_or_descending = 'd' THEN LEVEL END DESC;
p_num_triangle_rows := 20, p_ascending_or_desc := 'a':
TRIANGLE
--------------------------------------------------------------------------------
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
*********************
***********************
*************************
***************************
*****************************
*******************************
*********************************
***********************************
*************************************
***************************************
p_num_triangle_rows := 3, p_ascending_or_desc := 'd':
TRIANGLE
--------------------------------------------------------------------------------
*****
***
*
ETA: Here is a PL/SQL version that will do what you're after:
DECLARE
PROCEDURE produce_triangle_rows (p_num_triangle_rows IN NUMBER,
p_ascending_or_descending IN VARCHAR2 DEFAULT 'a')
IS
BEGIN
dbms_output.put_line('p_num_triangle_rows = '|| p_num_triangle_rows ||', p_ascending_or_descending = ' || p_ascending_or_descending);
FOR i IN 1..p_num_triangle_rows
LOOP
CASE WHEN p_ascending_or_descending = 'a' THEN
dbms_output.put_line(RPAD(' ', p_num_triangle_rows - i) || RPAD('*', i * 2 - 1, '*') || RPAD(' ', p_num_triangle_rows - i));
WHEN p_ascending_or_descending = 'd' THEN
dbms_output.put_line(RPAD(' ', i - 1) || RPAD('*', 2 * (p_num_triangle_rows - i) + 1, '*') || RPAD(' ', i - 1));
END CASE;
END LOOP;
END produce_triangle_rows;
BEGIN
produce_triangle_rows(p_num_triangle_rows => 5,
p_ascending_or_descending => 'a');
produce_triangle_rows(p_num_triangle_rows => 3,
p_ascending_or_descending => 'd');
END;
/
p_num_triangle_rows = 5, p_ascending_or_descending = a
*
***
*****
*******
*********
p_num_triangle_rows = 3, p_ascending_or_descending = d
*****
***
*
Note that I've wrapped the procedure in an anonymous block purely so I could call it with different parameters. You would just create the produce_triangle_rows procedure on its own and then call it appropriately.
Try this
declare #count int,#num int,#num1 int, #space int, #str varchar(50)
set #count = 3 set #num = 1
while(#num<=#count)
begin
set #num1 = 0 set #space = #count-#num
while (#num1<#num)
begin
if #str is null
set #str = '* '
else
set #str = #str+'* ' set #num1 = #num1+1
end
print (space(#space)+#str)
set #num = #num+1 set #str = null
end
Or
Declare #x varchar(20)=0,#y varchar(20)=5
while(#y>0)
begin
print space(#y)+replicate('*',#x)+replicate('*',#x+1)
set #y=#y-1
set #x=#x+1
end
I found the problem fun, so I solved it in PostgreSQL. Unfortunately repeating characters seems not really be a standardized feature. Here are the syntax to use for the most common RDBMSes:
PostgreSQL : repeat('*', n)
Oracle : rpad('', n, '*')
MS SQL Server : replicate('*', n)
MySQL : repeat('*', n)
First create some table with numbers up to whatever is the biggest triangle you can imagine:
create table n10 (n) as
select 0 union
select 1 union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9;
create table n1000 (n) as
select 100 * a1.n + 10 * a2.n + a3.n
from n10 a1 cross join n10 a2 cross join n10 a3;
Then to make a triangle of size 5 (replace 5 by any number between 0 and 1000 you want):
with s (s) as (select 5)
select
repeat(' ', s - n - 1) ||
repeat('*', 2 * n + 1) ||
repeat(' ', s - n - 1)
from n1000 cross join s
where n < s
order by n;
with s (s) as (select 5)
select
repeat(' ', s - n - 1) ||
repeat('*', 2 * n + 1) ||
repeat(' ', s - n - 1)
from n1000 cross join s
where n < s
order by n desc;
Good day Stackoverflow!
I have a query that is giving me an error: "Missing Right Parenthesis", at least, so says SQL Developer.
My query has a CASE statement within the WHERE clause that takes a parameter, and then executing a condition based on the value entered.
I've read that when using a CASE statement within a WHERE clause you have to surround the statement with parenthesis and assign it to a numeric value, e.g. "1", however doing so does not accomplish my goal.
My goal is to execute a condition in the CASE statement if that condition is met.
Would you mind taking a look and giving me some input please?
Thanks!
SELECT ...
FROM ....
WHERE 1 = 1
AND (
CASE :P_REPORT_PERIOD
WHEN 'SPRING'
THEN ((fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))-1) AND period >=10) OR (fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period < 4))
WHEN 'FALL'
THEN ((fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period >=4) OR (fiscal_year = (EXTRACT(YEAR FROM (SYSDATE))) AND period < 10))
END
) = 1
Problem Solved, THANKS to all those that attempted finding a solution.
Solution: Rather than using a CASE statement, I just created a stored procedure, replaced the CASE with IF and built a VSQL string from my query.
Example:
VSQL := 'SELECT.....'
IF (v_rpt_pd = 'SPRING') THEN
VSQL := VSQL || '( ( AND EXTRACT(YEAR FROM (SYSDATE))-1 = fiscal_year and period >=10) or ';
VSQL := VSQL || ' ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period <=3) )';
ELSE
VSQL := VSQL || '( ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period >=4) or ';
VSQL := VSQL || ' ( AND EXTRACT(YEAR FROM (SYSDATE)) = fiscal_year and period <=9) )';
END IF;
VSQL := VSQL ||' GROUP BY fiscal_year, period
and so on, if you want the entire solution, DM me and I'll send you the code.
Cheers!
As per Tom the CASE syntax in WHERE CLAUSE is -
--Syntax
select * from <table name>
where 1=1
and
(case
when <BOOLEAN_EXPRESSION>
then <SCALAR_RETURN_VALUE>
...
ELSE <SCALAR_RETURN_VALUE>
end) = <SCALAR_VALUE> ;
Example:
--Query
WITH SAMPLE_DATA AS
(select 100 COL1,999 COL2 from DUAL UNION ALL
select 200 COL1,888 COL2 from DUAL
)
SELECT * FROM SAMPLE_DATA
WHERE 1=1
AND (
CASE COL2
WHEN 999 THEN 1
ELSE 0
END
) = 1 ;
-- Output:
100 999
I am querying the DB to get all venues within a certain X Radius of a given latitude & longitude.
Everything works good until I insert a count & group by, causing the Having clause to no longer filter out records that are
SELECT
locations.id AS 'locations_id_c',
locations.city AS 'locations_city_c',
locations.province AS 'locations_state_c',
locations.latitude AS 'latitude_c',
locations.longitude AS 'longitude_c',
venues.id AS 'venues_id_c',
venues.name AS 'venues_name_c',
venues.venue_rank,
venues.median_fb_likes,
count(gigs.show_time),
count(band_profiles.name) AS 'Related Band',
#san fran lat & long = 37.7833° N, 122.4167° W
# ( 3959 * acos( cos( radians(37.7833) ) * cos( radians( locations.latitude) ) * cos( radians( locations.longitude ) - radians(-122.4167) ) + sin( radians(37.7833) ) * sin(radians(locations.latitude)) ) ) AS 'distance'
3956 * 2 * ASIN(SQRT( POWER(SIN((37.7833 - abs(locations.latitude)) * pi()/180/2),2) +COS(37.7833 * pi()/180 )*COS(abs(locations.latitude)*pi()/180) *POWER(SIN((locations.longitude + 122.4167)*pi()/180/2),2))) as 'distance'
FROM locations
INNER JOIN venues
ON locations.locatable_id = venues.id
AND venues.venue_rank >= 0
LEFT JOIN gigs
ON gigs.venue_id = venues.id
and gigs.show_time > NOW()
LEFT JOIN band_profiles
ON gigs.account_id = band_profiles.account_id
and band_profiles.name IS NOT NULL
WHERE
locations.locatable_type = 'Venue'
group by venues.id
HAVING distance < 50
ORDER BY venues.venue_rank DESC, distance DESC;
got it working
Seems the group by must happen on the main table, and not one of the joins.
Does anyone have an explanation why this is so?
I have a database of places which I store the latitude and longitude for. I want to query the database to find all places within a radius ($requestedDistance) of a specific latitude ($latitude) and longitude ($longitude).
The below query works and returns only those places within this radius, however how would I order them by distance so the closest is first? In the past, using raw SQL I have done the calculation within the SELECT statement and set it as 'distance' and then used HAVING distance < $requestedDistance ORDER BY distance, however I'm not sure how to add the calculation to the SELECT query using Doctrine Repository.
$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->add('where','l.enabled = 1')
->andWhere('( 3959 * acos( cos( radians('.$latitude.') )
* cos( radians( l.latitude ) )
* cos( radians( l.longitude )
- radians('.$longitude.') )
+ sin( radians('.$latitude.') )
* sin( radians( l.latitude ) ) ) ) < '.$requestedDistance);
$result= $d->getQuery();
UPDATE
I've tried the following query thanks to #Lazy Ants:
$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->select('l')
->addSelect(
'( 3959 * acos(cos(radians(' . $latitude . '))' .
'* cos( radians( l.latitude ) )' .
'* cos( radians( l.longitude )' .
'- radians(' . $longitude . ') )' .
'+ sin( radians(' . $latitude . ') )' .
'* sin( radians( l.latitude ) ) ) ) as distance'
)
->andWhere('l.enabled = :enabled')
->setParameter('enabled', 1)
->andWhere('distance < :distance')
->setParameter('distance', $requestedDistance)
->orderBy('distance', 'ASC');
However, it returns the following error:
`An exception occurred while executing 'SELECT COUNT(*) AS dctrn_count FROM
(SELECT DISTINCT il0 FROM (SELECT l0_.id AS il0, l0_.name AS name2, l0_.address1
AS address14, l0_.address2 AS address25, l0_.postcode AS postcode6, l0_.town AS
town7, l0_.county AS county8, l0_.enabled AS enabled11, l0_.date_created AS
date_created12, l0_.date_modified AS date_modified13, l0_.latitude AS
latitude19, l0_.longitude AS longitude20, 3959 * ACOS(COS(RADIANS(53.51331889999999))
* COS(RADIANS(l0_.latitude)) * COS(RADIANS(l0_.longitude) -
RADIANS(-2.935331099999985)) + SIN(RADIANS(53.51331889999999)) *
SIN(RADIANS(l0_.latitude))) AS sclr21 FROM locations l0_ WHERE l0_.enabled = ?
AND sclr21 < ? ORDER BY sclr21 ASC) dctrn_result) dctrn_table' with params
{"1":1,"2":30}:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr21' in 'where clause'`
$d = $this->getDoctrine()->getRepository('XXXWebsiteBundle:Locations')->createQueryBuilder('l');
$d
->select('l')
->addSelect(
'( 3959 * acos(cos(radians(' . $latitude . '))' .
'* cos( radians( l.latitude ) )' .
'* cos( radians( l.longitude )' .
'- radians(' . $longitude . ') )' .
'+ sin( radians(' . $latitude . ') )' .
'* sin( radians( l.latitude ) ) ) ) as distance'
)
->andWhere('l.enabled = :enabled')
->setParameter('enabled', 1)
->having('distance < :distance')
->setParameter('distance', $requestedDistance)
->orderBy('distance', 'ASC');
You are using andWhere() without a where().
Replace the andWhere() with a where().
Please check also in your Entity definition if some property is mapped on a column called "sclr21", so you can discovery also on which property do you have the issue.