In Azure Stream analytics Query giving error in CASE statement - azure-stream-analytics

I have some input data coming. There are 3 columns, fqn, v and t. The column v can have a string value or a number. If the fqn is like %production% then the v will be a number else it is a string. So I would have data like
FQN,V,T
productioncount,23,time
state,RUN,time
productioncount,45,time etc
So I hve a case clause in the stream analytics query, but it looks like the other fqn's(which have v values like RUN etc) are also being processed. I get the following error
"Cannot cast value 'RUN' to type 'bigint' in expression 'cast ( v as BIGINT )'.."
My query is as follows
SELECT
CASE
WHEN fqn like '%Production%' THEN ( max(cast(v as BIGINT))-(min(cast(v as BIGINT))))
ELSE MAX(V)
END AS V,
fqn,min(t) as timeslot
INTO
[finalalloutput]
FROM
[finalallinput] timestamp by t
group by TumblingWindow(minute, 1),fqn
Also I would like to change
ELSE MAX(V)
to reflect the TOP value. Maybe Max(V) would also give me an error because it is a string.

You need to apply CASE WHEN ... END logic over aggregate function arguments, not over aggregate function results. Otherwise max is computed over all values and is causing the error you quoted.
Another problem is that Stream Analytics does not support max aggregate function over string values. What is your expectation when you apply MAX over string values? What are you trying to compute in your scenario?
Here is a query that computes same results for "Production" values as your query and returns last non-production event in the window:
WITH Step1 AS
(
SELECT *, CASE WHEN fqn LIKE '%Production%' THEN 1 ELSE 0 END AS IsProduction
FROM [finalallinput] TIMESTAMP BY t
),
Step2 AS
(
SELECT
MAX (CASE WHEN isProduction = 1 THEN cast(v AS BIGINT) ELSE NULL END) - MIN(CASE WHEN IsProduction = 1 THEN cast(v AS BIGINT) ELSE NULL END) AS ProductionV,
TopOne() OVER (ORDER BY IsProduction ASC, t DESC) lastNonProductionEvent
,fqn
,min(t) AS timeslot
FROM Step1
GROUP BY
TumblingWindow(minute, 1)
,fqn
)
SELECT
fqn, timeslot, ProductionV, lastNonProductionEvent.v NonProductionV
INTO [finalalloutput]
FROM Step2

Related

How to do calculations and then compare them in SQL Server

I have a table with columns Recordnumber, Test, Value, Date and Complement. Recordnumber and test are the primary key.
I need compare values from TW01SS and TW01D1+TW01D2 with the same Recordnumber and depending on which value is bigger add it to Complement column. Any ideas?
Thank you
You can create two CTE's, one to get the SS count and the other the D1+D2 count then UPDATE the Complement column by the Recordnumber.
See WITH common_table_expression (Transact-SQL)
Specifies a temporary named result set, known as a common table
expression (CTE). This is derived from a simple query and defined
within the execution scope of a single SELECT, INSERT, UPDATE, DELETE
or MERGE statement. This clause can also be used in a CREATE VIEW
statement as part of its defining SELECT statement. A common table
expression can include references to itself. This is referred to as a
recursive common table expression.
;WITH
D1D2_Count
AS
-- Define D1+D2 Count CTE Query.
(
SELECT RecordNumber AS D1D2_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS D1D2_Total
FROM TestA
WHERE Test LIKE '%D1' OR Test LIKE '%D2'
),
SS_Count
AS
-- Define SS Count CTE Query.
(
SELECT RecordNumber AS SS_ID,
SUM(Value) OVER(PARTITION BY RecordNumber) AS SS_Total
FROM TestA
WHERE Test LIKE '%SS'
)
UPDATE A
SET Complement =
CASE WHEN D1D2_Total > SS_Total
THEN D1D2_Total
ELSE SS_Total
END
FROM TestA AS A
LEFT JOIN D1D2_Count ON RecordNumber = D1D2_ID
LEFT JOIN SS_Count ON RecordNumber = SS_ID
See Fiddle.
Optionally, you can add a WHERE clause to the end of the UPDATE statement so that it'll only update the Complement that has the greater total
If D1+D2 > SS, UPDATE Only the D1+D2 rows
Otherwise, UPDATE Only the SS rows.
Like this:
WHERE Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D1'
ELSE '%SS'
END
OR Test LIKE
CASE WHEN D1D2_Total > SS_Total
THEN '%D2'
ELSE '%SS'
END
select *, case when SS >= DX then SS else DX end
from T cross apply (values (
sum(case when Test = 'TW01SS1' then Value end)
over (partition by RecordNumber),
sum(case when Test like 'TW01D[12]' then Value end)
over (partition by RecordNumber))
) s(SS, DX);
You can use else coalesce(DX, SS) if null/missing tests are at play.
As an update:
update T
set Complement = (
select case when SS >= DX then SS else DX end
from T t2 cross apply (values (
sum(case when Test = 'TW01SS1' then Value end),
sum(case when Test like 'TW01D[12]' then Value end)
) s(SS, DX)
where t2.RecordNumber = T.RecordNumber
);

Create a new table with columns with case statements and max function

I have some problems in creating a new table from an old one with new columns defined by case statements.
I need to add to a new table three columns, where I compute the maximum based on different conditions. Specifically,
if time is between 1 and 3, I define a variable max_var_1_3 as max((-1)*var),
if time is between 1 and 6, I define a variable max_var_1_6 as max((-1)*var),
if time is between 1 and 12, I define a variable max_var_1_12 as max((-1)*var),
The max function needs to take the maximum value of the variable var in the window between 1 and 3, 1 and 6, 1 and 12 respectively.
I wrote this
create table new as(
select t1.*,
(case when time between 1 and 3 then MAX((-1)*var)
else var
end) as max_var_1_3,
(case when time between 1 and 6 then MAX((-1)*var)
else var
end) as max_var_1_6,
(case when time between 1 and 12 then MAX((-1)*var)
else var
end) as max_var_1_12
from old_table t1
group by time
) with data primary index time
but unfortunately it is not working. The old_table has already some columns, and I would like to import all of them and then compare the old table with the new one. I got an error that says that should be something between ) and ',', but I cannot understand what. I am using Teradata SQL.
Could you please help me?
Many thanks
The problem is that you have GROUP BY time in your query while trying to return all the other values with your SELECT t1.*. To make your query work as-is, you'd need to add each column from t1.* to your GROUP BY clause.
If you want to find the MAX value within the different time ranges AND also return all the rows, then you can use a window function. Something like this:
CREATE TABLE new AS (
SELECT
t1.*,
CASE
WHEN t1.time BETWEEN 1 AND 3 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 3 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_3,
CASE
WHEN t1.time BETWEEN 1 AND 6 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 6 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_6,
CASE
WHEN t1.time BETWEEN 1 AND 12 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 12 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_12,
FROM old_table t1
) WITH DATA PRIMARY INDEX (time)
;
Here's the logic:
check if a row falls in the range
if it does, return the desired MAX value for rows in that range
otherwise, just return that given row's default value (var)
return all rows along with the three new columns
If you have performance issues, you could also move the max_var calculations to a CTE, since they only need to be calculated once. Also to avoid confusion, you may want to explicitly specify the values in your SELECT instead of using t1.*.
I don't have a TD system to test, but try it out and see if that works.
I cannot help with the CREATE TABLE AS, but the query you want is this:
SELECT
t.*,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 3) AS max_var_1_3,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 6) AS max_var_1_6,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 12) AS max_var_1_12
FROM old_table t;

Only one expression can be specified in the select list w

I am having problem in part of my code anyway to do this
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. The update part is working but how to use insert into to calculate if a condition is not meant it will insert.
IF
/* CHECKLIST TO UPDATE*/
(NOT EXISTS
(SELECT *
FROM ENERGY.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
,ENERGY.D_CHECK_LIST D_CHECK_LIST
WHERE D_ENERGY_REFERENCE.ID = D_CHECK_LIST.ID
AND D_ENERGY_REFERENCE.REFERENCE = 19051
)
)
BEGIN
INSERT INTO DB.D_ENERGY_REFERENCE(ID, REFERENCE_NO, REFERENCE,VALUE_INTEGER)
(SELECT ID,
(SELECT ISNULL(MAX(REFERENCE_NO), 0) + 1 FROM DB.D_ENERGY_REFERENCE),
19051, (SELECT D_CHECK_LIST.ID,
CASE
WHEN CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT) = 0 THEN NULL
ELSE
(
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION IN (2, 3, 50001, 50003, 50004, 50005, 50006, 50020, 50027, 50028) THEN EVALUATION ELSE NULL END) AS FLOAT)
/
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT)
) * 100
END FROM DB.D_CHECK_LIST
GROUP BY D_CHECK_LIST.ID)
FROM DB.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
WHERE D_ENERGY_REFERENCE.ID = ID AND D_ENERGY_REFERENCE.REFERENCE = 19051
GROUP BY D_ENERGY_REFERENCE.ID
)
END
Can you please check this following part in the sub query of your script-
.......
19051,
(
SELECT
D_CHECK_LIST.ID, -- This is the column 1
CASE
WHEN -- Here you are generating column 2 in the sub query
......
)
Here you are selecting 2 column - one is "D_CHECK_LIST.ID" and other one is generation through CASE WHEN statement. I think you should SELECT any 1 column from those 2 column. If both are required, you can use separate Sub query for that.
The ERROR code "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS" is self explanatory that you can not implement a Sub Query with more than 1 column selected unless the Sub Query is using inside EXISTS method.

Error in sql query when using contains in aggregate expression

Query:
SELECT
c,
COUNT
( WHEN a='11' AND contains(b,'aa') THEN 1 ELSE NULL END
) as total
from x
group by c
Error:
Full-text predicates cannot appear in an aggregate expression. Place
the aggregate expression in a subquery.
I am using contains because, it uses the index when searching in text, also the query is like that only, so i have to put it in aggregate expression only.... please suggest..
Try this one -
SELECT total = COUNT(
CASE WHEN a = '11'
AND CONTAINS(b, 'aa') THEN 1
END)
FROM x
CONTAINS can appear only in a WHERE clause
SELECT
c,
COUNT(ContainsResult) AS total
FROM
(
SELECT
c, CASE WHEN a='11' THEN 1 ELSE NULL END AS ContainsResult
from
x
WHERE
contains(b,'aa')
UNION ALL
SELECT
c, NULL
from
x
WHERE
NOT contains(b,'aa')
) X1
GROUP BY
c

Choose grouping value based on condition

I need to construct a query which meets the following criteria:
select X columns and MAX(column1), group by X columns
if column1 contains negative value (can be only one in given group), then instead of MAX(column1) display 'reset'
I know I can do it by using case before grouping and substituting negative values with a very large number and then using case after grouping, but this is an awfully messy solution.
Does anybody have a better idea how to solve this?
You can additionally select the minimum value and check that for negativity.
Something like the following:
select foo, case when min_value < 0 then 'reset' else to_char(max_value) end
from
(
select foo, max(column1) as max_value, min(column1) as min_value
from your_table
group by foo
)
Or, without the sub query:
select foo, case when min(column1) < 0 then 'reset' else to_char(max(column1)) end
from your_table
group by foo