Case expression in json_build_object() - sql

I want to add a case expression inside of my json_build_object for the times where and endtime has not yet been set.
CODE
Current
SELECT json_build_object(
'endtime', json_agg(CONCAT(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )),
'starttime', json_agg(CONCAT(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )),
'totaltime', json_agg(starttime::timestamp - endtime::timestamp),
)
FROM jobs
Expected
SELECT json_build_object(
'endtime', json_agg(CONCAT(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )),
'starttime', json_agg(CONCAT(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )),
CASE WHEN endtime IS NULL
THEN 'totaltime', json_agg(starttime::timestamp - NOW()::timestamp)
ELSE 'totaltime', json_agg(starttime::timestamp - endtime::timestamp)
END
)
FROM jobs
RESULT
Current
{
"endtime" : [" ", "2019-07-22 18:50:06", "2019-07-19 19:24:13", "2019-07-19 16:23:46"],
"starttime" : ["2019-07-24 16:02:49", "2019-07-22 20:12:01", "2019-07-19 16:55:55", "2019-07-19 14:56:48"],
"totaltime" : [null, "01:21:55.150273", "-02:28:17.795901", "-01:26:57.872932"]
}
Expected
When the endtime is null I would like like the totaltime to be the time till now
{
"endtime" : [" ", "2019-07-22 18:50:06", "2019-07-19 19:24:13", "2019-07-19 16:23:46"],
"starttime" : ["2019-07-24 16:02:49", "2019-07-22 20:12:01", "2019-07-19 16:55:55", "2019-07-19 14:56:48"],
"totaltime" : ["01:2..timeTillNow", "01:21:55.150273", "-02:28:17.795901", "-01:26:57.872932"]
}

Because you're using aggregated functions, if you put the case when endtime around the json_agg, you're checking the value of the aggregated endtime and it must be in a group by.
Instead, just like the concat, the case goes inside the json_agg. This expression will be evaluated for each row to provide json_agg with the values to aggregate.
SELECT json_build_object(
'endtime', json_agg(
concat(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )
),
'starttime', json_agg(
concat(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )
),
'totaltime', json_agg(
case when endtime is null
then starttime::timestamp - NOW()::timestamp
else starttime::timestamp - endtime::timestamp
end
)
)
FROM jobs;

Related

Create nested json in Snowflake

I am trying to create a nested json in Snowflake and have narrowed down the query like below where I have nested it on id. However, I want the nested json to also apply to the inner layer and I am finding it hard to get the right query for it.
WITH subquery AS (
SELECT id, placeId, actionId, resultValue
FROM my_table
)
SELECT id,
'{"resultValues": {' || listagg('"' || placeId || '": {"' || actionId || '": ' || resultValue || '}', ',') within group (order by placeId) || '}}' as nested_json
FROM subquery
GROUP BY id;
Below is how the current result is looking like for each id.
I am trying to get the actionId1 and actionId2 grouped under the placeId1 and placeId2 so that it looks like below. How do I get this done? Any ideas would be appreciated.
Meet FLATTEN() and LATERAL they like to hang out with OBJECT_AGG() who needs his own space via CTE's.
WITH CTE AS (
SELECT
parse_json(
' { "resultValues": [
{ "placeId1": { "actionId1": 1.1 } }, { "placeId1": { "actionId2": 1.2 } },
{ "placeId2": { "actionId1": 1.3 } }, { "placeId2":{ "actionId2": 1.4} } ] }'
) VOLIA
),
CTE2 AS (
SELECT
DISTINCT KIAORA.PATH KIAORA,
TE_REO.PATH TE_REO,
OBJECT_AGG(MAORI.PATH, MAORI.VALUE) OVER (PARTITION BY TE_REO.PATH) MAORI
FROM
CTE,
LATERAL FLATTEN(INPUT => VOLIA) KIAORA,
LATERAL FLATTEN(KIAORA.VALUE) HELLO,
LATERAL FLATTEN(HELLO.VALUE) TE_REO,
LATERAL FLATTEN (INPUT => TE_REO.VALUE) MAORI
)
SELECT
DISTINCT OBJECT_CONSTRUCT(
KIAORA,
ARRAY_CONSTRUCT(
OBJECT_AGG(TE_REO, MAORI) OVER (PARTITION BY KIAORA)
)
) ANSWER,
VOLIA
FROM
CTE2, CTE
after starting :

How to use JSON_EXTRACT without having a key name?

how do I extract value frm key "Nome" from JSON using JSON_EXTRACT in google bigquery?
I cannot use the key 135 in the query because it is dynamic (Like this JSON_EXTRACT(vista, '$.Agencia.135.Nome'))
How to use JSON_EXTRACT without having a key '135' name?
JSON Record Sample:
{
"Campanha": "Campanha A",
"Ad": "Ad A",
"Agencia": {
"135": {
"Celular": ".",
"Codigo": "135",
"CodigoPai": "105",
"DDD": "00",
"Email": "email-A#email.com",
"Nome": "Nome A",
"Fone": "00 0000.0000",
"Fone2": ".",
"Foto": "foto-A.jpg"
}
}
}
Not sure if your json is formatted correctly. Is the key '135' an array? If so, format it properly and you can access it as the example below:
SELECT JSON_EXTRACT(json_text, '$.Agencia.135[1]') AS nome
FROM UNNEST([
'{"Agencia":{"135":[{"Codigo":"135"},{"Nome":"Nome A"}]}}'
]) AS json_text;
That would give you:
[
{
"nome": "{\"Nome\":\"Nome A\"}"
}
]
For more references about the JSON_EXTRACT: https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_extract
Use below approach
execute immediate (
select string_agg("select " || key || ''' key
, JSON_EXTRACT_SCALAR(vista, '$.Agencia.''' || key || '''.Nome') AS Nome
from `project.dataset.table`''', " union all ")
from `project.dataset.table`, unnest(regexp_extract_all(regexp_replace(JSON_EXTRACT(vista, '$.Agencia'), r':{.*?}+', ''), r'"(.*?)"')) key
);
If applied to sample data in your question - output is
Also, depends on your use case - you might try below option too
execute immediate (
select 'select * from (' || string_agg("select " || key || ''' key
, JSON_EXTRACT_SCALAR(vista, '$.Agencia.''' || key || '''.Nome') AS Nome
from `project.dataset.table`''', " union all ") || ') where not Nome is null'
from `project.dataset.table`, unnest(regexp_extract_all(regexp_replace(JSON_EXTRACT(vista, '$.Agencia'), r':{.*?}+', ''), r'"(.*?)"')) key
);

Map in BigQuery (dynamic keys)

In bigquery, if we are interested in constructing json output, we can usually use struct for json object when the keys are known beforehand.
SELECT TO_JSON_STRING(STRUCT(key1))
FROM (SELECT "val1" as key1 UNION ALL
SELECT "val2" as key1)
Result
{"key1":"val1"}
{"key1":"val2"}
But in the case where the keys are dynamic, we really want a map type, similar to the avro map type
For example
SELECT *
FROM (SELECT "key1" as key, "val1" as val UNION ALL
SELECT "key2" as key, "val2" as val)
should return
{"key1": "val1", "key2": "val2"}
is there anyway to achieve this using BigQuery SQL?
Below is for BigQuery Standard SQL
Something simple like below should produce expected result
#standardSQL
WITH `project.dataset.table` AS (
SELECT "key1" AS key, "val1" AS val UNION ALL
SELECT "key2" AS key, "val2" AS val
)
SELECT '{' || STRING_AGG(REPLACE(TRIM(FORMAT('%T', t), '()'), '", "', '": "'), ', ') || '}' AS return
FROM `project.dataset.table` t
with output
Row return
1 {"key1": "val1", "key2": "val2"}
You can use Dynamic SQL to generate JSON string:
DECLARE
JSONSTR STRING;
SET
JSONSTR = (
SELECT
'{' || STRING_AGG('"' || key || '": "' || val || '"', ', ') || '}'
FROM (
SELECT *
FROM (SELECT "key1" AS key, "val1" AS val
UNION ALL
SELECT "key2" AS key, "val2" AS val)));
EXECUTE IMMEDIATE
FORMAT("""SELECT '%t'""",JSONSTR);

MVC SQL invalid

I have the following code in my MVC Index function. It is called from a search page that allows the user to search for various string values:
public ViewResult Index(string sortOrder, string YearString,string MonthString,string BudgetTypeString,string DescriptionString)
{
ViewBag.BudgetTypeSortParm = String.IsNullOrEmpty(sortOrder) ? "BudgetType_desc" : "";
ViewBag.MonthSortParm = sortOrder == "Date" ? "Month_desc" : "Month";
ViewBag.YearSortParm = sortOrder == "Date" ? "Year_desc" : "Year"; // 12-24-2014 JR added
ViewBag.DescriptionSortParm = sortOrder == "Description" ? "Description_desc" : "Description";
var budg = from s in db.budgets
select s;
if (!String.IsNullOrEmpty(YearString) ||
!String.IsNullOrEmpty(MonthString) ||
!String.IsNullOrEmpty(BudgetTypeString) ||
!String.IsNullOrEmpty(DescriptionString))
{
budg = budg.Where(s => s.BudgetType.ToUpper().Contains(BudgetTypeString.ToUpper()) ||
String.IsNullOrEmpty(BudgetTypeString) || s.Description.ToUpper().Contains(DescriptionString.ToUpper()) ||
String.IsNullOrEmpty(DescriptionString) ||
s.Month.ToUpper().Contains(MonthString.ToUpper()) ||
String.IsNullOrEmpty(MonthString) ||
s.Year.ToUpper().Contains(YearString.ToUpper()) ||
String.IsNullOrEmpty(YearString));
budg = budg.OrderBy(s => s.BudgetType);
return View(db.budgets.ToList());
}
}
Here is the actual SQL that is converted from the above code:
budg {SELECT
[Extent1].[id] AS [id],
[Extent1].[BudgetType] AS [BudgetType],
[Extent1].[Description] AS [Description],
[Extent1].[Amount] AS [Amount],
[Extent1].[Month] AS [Month],
[Extent1].[Year] AS [Year],
[Extent1].[DateStamp] AS [DateStamp]
FROM [dbo].[budget] AS [Extent1]
WHERE (( CAST(CHARINDEX(UPPER(#p__linq__0),
UPPER([Extent1].[BudgetType])) AS int)) > 0) OR
(( CAST(CHARINDEX(UPPER(#p__linq__1), UPPER([Extent1].[Description])) AS int)) > 0) OR
(( CAST(CHARINDEX(UPPER(#p__linq__2), UPPER([Extent1].[Month])) AS int)) > 0) OR
(( CAST(CHARINDEX(UPPER(#p__linq__3), UPPER([Extent1].[Year])) AS int)) > 0)}
Does anyone know why my strings are incorrectly being converted into integers and how to correct it so the search strings on my search page work correctly?
Let's take a look at just one of the Cast statements:
( CAST(CHARINDEX(UPPER(#p__linq__1), UPPER([Extent1].[Description])) AS int)) > 0)
Take a look at the inner statement. It's actually getting the CharIndex of one string in the other. Basically, does "Description" contain #p__linq__1. CharIndex returns 0 if if the first expression is not found in the other. The result of CharIndex is what is being Cast as int, and then compared to see if it is greater than 0. Which is exactly what you asked it to do when you use .Contains

MDX - Extract Last 24 hours data

I need to extract last 24 hours data from a cube. Below is the MDX I have written but it doesn't return the data according to current time (system time).
SELECT
[Date].[Calender-Year_Quarter_Month_Date].[Date] ON ROWS
,{[Measures].[Delay In Mintues]} ON COLUMNS
FROM
(
SELECT
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now() - 1
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
:
[Time].[Time-Hour_Time].[Hour].&[23].&[23:59]
)
}
+
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now()
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&[0].&[00:00]
:
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
)
} ON COLUMNS
FROM [Delay Reasons]
);
(note: not tested)
Does this work?
SELECT
[Date].[Calender-Year_Quarter_Month_Date].[Date] ON ROWS
,{[Measures].[Delay In Mintues]} ON COLUMNS
FROM [Delay Reasons]
WHERE
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now() - 1
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
:
[Time].[Time-Hour_Time].[Hour].&[23].&[23:59]
)
}
+
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now()
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&[0].&[00:00]
:
StrToMember
(
"[Time].[Time-Hour_Time].[Hour].&[" + Format(Now(),"HH") + "].&[00:00]"
)
)
};