I have a column (text) in my Postgres DB (v.10) with a JSON format.
As far as i now it's has an array format.
Here is an fiddle example: Fiddle
If table1 = persons and change_type = create then i only want to return the name and firstname concatenated as one field and clear the rest of the text.
Output should be like this:
id table1 did execution_date change_type attr context_data
1 Persons 1 2021-01-01 Create Name [["+","name","Leon Bill"]]
1 Persons 2 2021-01-01 Update Firt_name [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
1 Users 3 2021-01-01 Create Street [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
Disassemble json array into SETOF using json_array_elements function, then assemble it back into structure you want.
select m.*
, case
when m.table1 = 'Persons' and m.change_type = 'Create'
then (
select '[["+","name",' || to_json(string_agg(a.value->>2,' ' order by a.value->>1 desc))::text || ']]'
from json_array_elements(m.context_data::json) a
where a.value->>1 in ('name','firstname')
)
else m.context_data
end as context_data
from mutations m
modified fiddle
(Note:
utilization of alphabetical ordering of names of required fields is little bit dirty, explicit order by case could improve readability
resulting json is assembled from string literals as much as possible since you didn't specified if "+" should be taken from any of original array elements
the to_json()::text is just for safety against injection
)
I have a query like (simplified):
SELECT
JSON_QUERY(r.SerializedData, '$.Values') AS [Values]
FROM
<TABLE> r
WHERE ...
The result is like this:
{ "2019":120, "20191":120, "201902":121, "201903":134, "201904":513 }
How can I remove the entries with a key length less then 6.
Result:
{ "201902":121, "201903":134, "201904":513 }
One possible solution is to parse the JSON and generate it again using string manipulations for keys with desired length:
Table:
CREATE TABLE Data (SerializedData nvarchar(max))
INSERT INTO Data (SerializedData)
VALUES (N'{"Values": { "2019":120, "20191":120, "201902":121, "201903":134, "201904":513 }}')
Statement (for SQL Server 2017+):
UPDATE Data
SET SerializedData = JSON_MODIFY(
SerializedData,
'$.Values',
JSON_QUERY(
(
SELECT CONCAT('{', STRING_AGG(CONCAT('"', [key] ,'":', [value]), ','), '}')
FROM OPENJSON(SerializedData, '$.Values') j
WHERE LEN([key]) >= 6
)
)
)
SELECT JSON_QUERY(d.SerializedData, '$.Values') AS [Values]
FROM Data d
Result:
Values
{"201902":121,"201903":134,"201904":513}
Notes:
It's important to note, that JSON_MODIFY() in lax mode deletes the specified key if the new value is NULL and the path points to a JSON object. But, in this specific case (JSON object with variable key names), I prefer the above solution.
I did ask this question before but deleted the post.
Here is my question: I have a table in SQL Server with multiple events in the table, I am trying to filter on the events and the datetime between the events on a certain X min.
I need help with T-SQL queries.
What can use use to do the following (any links will be appreciated):
take event_id and datetime of device, compare to a list of other event_id's to see if there are any other events withing the last 24 min for that device.
What would work for me? Nested queries? Where clause? CTE?
I have tried 6 queries but not getting the result I need, do I use (max) datetime and then compare on event_ID's?
I know this is not much but any help or links would be appreciated....
On Request (Full Query no changes)
1.
SELECT A.[Unit_id]
,A.[TransDate]
,A.[event_id]
,A.[event_msg]
,B.[TransDate]
,B.[event_id]
,B.[event_msg]
FROM
(Select
A.[Unit_id]
,MAX(A.[TransDate]) AS Transdate
,A.[event_id]
,A.[event_msg]
FROM [JammingEvents].[dbo].[EventLogExtended] AS A
WHERE event_id = '345'
GROUP BY A.[Unit_id]
,A.[event_id]
,A.[event_msg]
) AS A
INNER JOIN
(SELECT
B.[Unit_id]
,MAX(B.[TransDate]) AS Transdate
,B.[event_id]
,B.[event_msg]
FROM [JammingEvents].[dbo].[EventLogExtended] AS B
WHERE B.event_id = '985'
GROUP BY B.[Unit_id]
,B.[event_id]
,B.[event_msg]
) AS B
ON
A.Unit_id = B.Unit_id
WHERE (B.TransDate BETWEEN DATEADD(MINUTE,-24,A.Transdate) AND DATEADD(MINUTE,24,A.Transdate))
this works but only if you compare 2 event Id's. the problem is i need to do this on a bulk scale.
2.
SET NOCOUNT ON
GO
SELECT MAX(ELE.Transdate) AS Transdate
,ELE.[Unit_id]
,ELE.[event_id]
,ELE.[event_msg]
,ELE.[Latitude]
,ELE.[Longitude]
,ELE.[date_ack]
,ELE.[user_id_ack]
,ELE.[date_closed]
,ELE.[user_id_closed]
,ELE.[action]
,ELE.[EventSeqNo]
,ELE.[MsgSeqNo]
,ELE.[Speed]
,ELE.[Heading]
,ELE.[Status1]
,ELE.[Status2]
,ELE.[GeoLocation]
,ELE.[Reg_No]
,ELE.[Company]
,ELE.[Fleet_Code]
,ELE.[IgnStatus]
,ELE.[comboActioned]
FROM
[JammingEvents].[dbo].[EventLogExtended] ELE
INNER JOIN
(
SELECT
F.Transdate ,F.[Unit_id] ,F.[event_id] ,F.[event_msg] ,F.[Latitude] ,F.[Longitude] ,F.[date_ack] ,F.[user_id_ack]
,F.[date_closed] ,F.[user_id_closed] ,F.[action] ,F.[EventSeqNo] ,F.[MsgSeqNo] ,F.[Speed] ,F.[Heading] ,F.[Status1]
,F.[Status2] ,F.[GeoLocation] ,F.[Reg_No] ,F.[Company] ,F.[Fleet_Code] ,F.[IgnStatus] ,F.[comboActioned]
FROM [JammingEvents].[dbo].[EventLogExtended] AS F
WHERE
F.event_id IN
('302'
,'303'
,'304'
,'305'
,'309'
,'340'
,'341'
,'345'
,'962'
,'963'
,'973'
,'974'
,'975'
,'976'
,'985'
,'987'
,'989'
,'C220'
,'C222'
,'C224'
,'C227'
,'C228')
) AS A
ON
ELE.Unit_id = A.Unit_id
INNER JOIN
(
SELECT
G.Transdate ,G.[Unit_id] ,G.[event_id] ,G.[event_msg] ,G.[Latitude] ,G.[Longitude] ,G.[date_ack]
,G.[user_id_ack] ,G.[date_closed] ,G.[user_id_closed] ,G.[action] ,G.[EventSeqNo] ,G.[MsgSeqNo] ,G.[Speed] ,G.[Heading]
,G.[Status1] ,G.[Status2] ,G.[GeoLocation] ,G.[Reg_No] ,G.[Company] ,G.[Fleet_Code] ,G.[IgnStatus] ,G.[comboActioned]
FROM [JammingEvents].[dbo].[EventLogExtended] AS G
WHERE
G.event_id = '345'
) AS B
ON
A.Unit_id = B.Unit_id
WHERE (ELE.TransDate BETWEEN DATEADD(MINUTE,-24,A.Transdate) AND DATEADD(MINUTE,24,A.Transdate))
AND
(ELE.event_id IN
(
'302'
,'303'
,'304'
,'305'
,'309'
,'340'
,'341'
,'345'
,'962'
,'963'
,'973'
,'974'
,'975'
,'976'
,'985'
,'987'
,'989'
,'C220'
,'C222'
,'C224'
,'C227'
,'C228'
))
AND
(ELE.action = '0')
GROUP BY ELE.TransDate
,A.Unit_id
,ELE.[Unit_id]
,ELE.[event_id]
,ELE.[event_msg]
,ELE.[Latitude]
,ELE.[Longitude]
,ELE.[date_ack]
,ELE.[user_id_ack]
,ELE.[date_closed]
,ELE.[user_id_closed]
,ELE.[action]
,ELE.[EventSeqNo]
,ELE.[MsgSeqNo]
,ELE.[Speed]
,ELE.[Heading]
,ELE.[Status1]
,ELE.[Status2]
,ELE.[GeoLocation]
,ELE.[Reg_No]
,ELE.[Company]
,ELE.[Fleet_Code]
,ELE.[IgnStatus]
,ELE.[comboActioned]
ORDER BY ELE.TransDate, ELE.Unit_id DESC
so far this got me the closest but i have no idea what to do, i am very poor with SQL syntax and writing queries.
You could use an exists subquery to demand that there was another event for the same device within the preceeding 24 minutes:
select *
from Events e1
where exists
(
select *
from Events e2
where e2.Device_ID = e1.Device_ID
and e2.event_dt between
dateadd(minute, e1.event_dt, -24)
and e1.event_dt
)
Self join should work as well:
SELECT *, DATEDIFF(minute,b.transdate,a.transdate) diff FROM EventLogWxtended a
JOIN eventLogExtended b
ON (a.unit_id=b.unit_id AND b.transdate<a.transdate
AND DATEDIFF(minute,b.transdate,a.transdate)<24)
I want to write the following T SQL query in MDX
Select count(bugs),priority from table
where
Case when priority =1 then startdate< dateadd(dd,-7,getdate())
when priority =2 then startdate< dateadd(dd,-14,getdate())
end
group by priority
Tried the following but not working
WITH MEMBER [Measures].CHECKING
AS
CASE [Item].[ startdate].CurrentMember
WHEN [Item].[ Priority].&[1] THEN [Item].[startdate]<DATEADD(DAY,-7,NOW())
WHEN [Item].[ Priority].&[2] THEN [Item].[startdate]<DATEADD(DAY,-14,NOW())
END
SELECT
NON EMPTY{[Measures].[Count], [Measures].CHECKING }ON COLUMNS
,NON EMPTY{([Item].[ Priority].[ Priority].ALLMEMBERS )}
I am new to MDX queries, any suggestions on how to approach this please..
Your CASE logic has a basic problem. The statement cannot result in a condition. It can only result in a value that you then compare to something else.
To take your tSQL example, I think it should read more like this:
Select count(bugs),priority from table
where
1 = Case when priority = 1 and startdate< dateadd(dd,-7,getdate()) Then 1
when priority = 2 and startdate< dateadd(dd,-14,getdate()) then 1
else 0 end
group by priority
A cleaner way to write this would be to skip the CASE altogether.
Select count(bugs),priority from table
where
(priority = 1 and startdate< dateadd(dd,-7,getdate()))
or
(priority = 2 and startdate< dateadd(dd,-14,getdate()))
group by priority
I am assuming the following:
Your startdate hierarchy is an attribute hierarchy, not a user hierarchy and
the current day is its last member.
Then the following MDX should deliver what you want:
SELECT
{ [Measures].[Count] }
ON COLUMNS
,
{ [Item].[ Priority].&[1], [Item].[ Priority].&[2] }
ON ROWS
FROM (
SELECT ({ [Item].[ Priority].&[1] }
*
([Item].[ startdate].[ startdate].Members
- Tail([Item].[ startdate].[ startdate].Members, 7)
)
)
+
({ [Item].[ Priority].&[2] }
*
([Item].[ startdate].[ startdate].Members
- Tail([Item].[ startdate].[ startdate].Members, 14)
)
)
ON COLUMNS
FROM [yourCube]
)
Your code [Item].[startdate]<DATEADD(DAY,-7,NOW()) does not work in MDX for several reasons: firstly, [Item].[startdate] is a hierarchy, and hence cannot be compared using <. Secondly, even if you would re-state it as [Item].[startdate].CurrentMember < DATEADD(DAY,-7,NOW()), you would have a member on the left side of the <, and a date , i. e. a value, on the right side. One of the important things to keep in mind with MDX are the different types of objects: Hierarchies, levels, members, tuples, sets. And all these are not values. You do not just have columns like in SQL.