insert into snowflake table from multiple values with arrays and objects - snowflake-cloud-data-platform

I'm trying to insert multiple rows with arrays and structs, via an SQL statement, into Snowflake.
To insert arrays of values into a column I am using the ARRAY_CONSTUCT function and to insert the structures/dictionaries/objects I am using the OBJECT_CONSTRUCT function.
E.g.
insert into "MY_DB"."MY_SCHEMA"."MY_TABLE"
("ID", "TS", "TEXT", "DATEONLY", "ARRAY", "OBJ", "BOOL", "DOUBLE", "INT", "DEC_18_9")
values
('id1', '2020-11-26 14:01:27.868', '19', '2020-11-26',
ARRAY_CONSTRUCT(0, 1, 2), OBJECT_CONSTRUCT('this', 'is', 'my', 'object', 'query',
OBJECT_CONSTRUCT('field1', 'one', 'field2', ARRAY_CONSTRUCT('field2a', 'two')),
'field3', ARRAY_CONSTRUCT(3, 4, 5)), FALSE, 178482300.96318725, 9, 12345619.876543190),
('id2', '2020-11-26 14:01:27.868', '19', '2020-11-26',
ARRAY_CONSTRUCT(0, 1, 2), OBJECT_CONSTRUCT('this', 'is', 'my', 'object', 'query',
OBJECT_CONSTRUCT('field1', 'one', 'field2', ARRAY_CONSTRUCT('field2a', 'two')),
'field3', ARRAY_CONSTRUCT(3, 4, 5)), FALSE, 178482300.96318725, 9, 12345619.876543190)
;
This results in an exception:
SQL compilation error: Invalid expression [ARRAY_CONSTRUCT(0, 1, 2)] in VALUES clause
Inserting a single row using this syntax works:
insert into "MY_DB"."MY_SCHEMA"."MY_TABLE"
("ID", "TS", "TEXT", "DATEONLY", "ARRAY", "OBJ", "BOOL", "DOUBLE", "INT", "DEC_18_9")
select 'id1', '2020-11-26 14:01:27.868', '19', '2020-11-26',
ARRAY_CONSTRUCT(0, 1, 2), OBJECT_CONSTRUCT('this', 'is', 'my', 'object', 'query',
OBJECT_CONSTRUCT('field1', 'one', 'field2', ARRAY_CONSTRUCT('field2a', 'two')),
'field3', ARRAY_CONSTRUCT(3, 4, 5)), FALSE, 178482300.96318725, 9, 12345619.876543190
;
However, it is unclear if and how this can be used for inserting multiple rows.
The table definition is:
create or replace temporary table "MY_DB"."MY_SCHEMA"."MY_TABLE"
("ID" STRING NOT NULL, "TS" TIMESTAMP NOT NULL, "TEXT" STRING,
"DATEONLY" DATE, "ARRAY" ARRAY, "OBJ" OBJECT, "BOOL" BOOLEAN,
"DOUBLE" DOUBLE, "INT" BIGINT, "DEC_18_9" NUMBER (18, 9)
);
What is the correct way to do this?
(Do I need to spill the data into a file and load from there or is there a direct way to do this?)
The only mention of this I found was in an "answer" here.
To clarify, I am inserting data into a temporary table, from which I merge into another table, since I could not find a way to merge data via an SQL statement from values (i.e. not from a table).

Via trial and error, I found this solution:
INSERT INTO "MY_DB"."MY_SCHEMA"."MY_TABLE"
SELECT $1, $2, $3, $4, PARSE_JSON($5), PARSE_JSON($6), $7, $8, $9, $10
from values
('id1', '2020-11-26 14:01:27.868', '19', '2020-11-26', '[0, 1, 2]',
'{"this": "is", "my": "object",
"query": {"field1": "one", "field2": ["field2a", "two"], "field3": [3, 4, 5]}}',
FALSE, 178482300.96318725, 9, 12345619.876543190),
('id2', '2020-11-26 14:01:27.868', '19', '2020-11-26', '[0, 1, 2]',
'{"this": "is", "my": "object",
"query": {"field1": "one", "field2": ["field2a", "two"], "field3": [3, 4, 5]}}',
FALSE, 178482300.96318725, 9, 12345619.876543190)
;
FYI, from a brief testing, Snowflake identifies NaN, -inf and inf within the JSON without the quotes around them as floating point values e.g. {"my_field": NaN}.

VALUES does not support ARRAY_CONSTRUCT expression, this is why you get "Invalid expression" error:
https://docs.snowflake.com/en/sql-reference/constructs/values.html#syntax
Most simple arithmetic expressions and string functions can be
evaluated at compile time, but most other expressions cannot.
You may use SELECT + UNION ALL instead of VALUES:
insert into "MY_DB"."MY_SCHEMA"."MY_TABLE"
("ID", "TS", "TEXT", "DATEONLY", "ARRAY", "OBJ", "BOOL", "DOUBLE", "INT", "DEC_18_9")
SELECT 'id1', '2020-11-26 14:01:27.868', '19', '2020-11-26',
ARRAY_CONSTRUCT(0, 1, 2), OBJECT_CONSTRUCT('this', 'is', 'my', 'object', 'query',
OBJECT_CONSTRUCT('field1', 'one', 'field2', ARRAY_CONSTRUCT('field2a', 'two')),
'field3', ARRAY_CONSTRUCT(3, 4, 5)), FALSE, 178482300.96318725, 9, 12345619.876543190
UNION ALL
SELECT 'id2', '2020-11-26 14:01:27.868', '19', '2020-11-26',
ARRAY_CONSTRUCT(0, 1, 2), OBJECT_CONSTRUCT('this', 'is', 'my', 'object', 'query',
OBJECT_CONSTRUCT('field1', 'one', 'field2', ARRAY_CONSTRUCT('field2a', 'two')),
'field3', ARRAY_CONSTRUCT(3, 4, 5)), FALSE, 178482300.96318725, 9, 12345619.876543190;

Related

Is there a better way to extract values from this JSON?

I have found this example in https://www.sqlshack.com/extract-scalar-values-from-json-data-using-json_value/
DECLARE #data NVARCHAR(4000);
SET #data = N'{
"Employees": [
{
"EmpName": "Rohan Sharma",
"Department": "IT",
"Address": "101, Sector 5, Gurugram, India",
"Salary": 100000
},
{
"EmpName": "Manohar Lal",
"Department": "Human Resources",
"Address": "17, Park Avenue, Mumbai, India",
"Salary": 78000
}
]
}';
SELECT JSON_VALUE(#data, '$.Employees[0].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[0].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[0].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[0].Salary') AS 'Salary'
UNION ALL
SELECT JSON_VALUE(#data, '$.Employees[1].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[1].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[1].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[1].Salary') AS 'Salary'
So I wonder if there are better ways to get all values in JSON without telling $.Employees indexes?
Example, if I have N components in this JSON, I don't want to have to UNION ALL N times.
In my project there will be like more than 40 components in a single JSON.
DECLARE #data NVARCHAR(4000);
SET #data = N'{
"Employees": [
{
"EmpName": "Rohan Sharma",
"Department": "IT",
"Address": "101, Sector 5, Gurugram, India",
"Salary": 100000
},
{
"EmpName": "Manohar Lal",
"Department": "Human Resources",
"Address": "17, Park Avenue, Mumbai, India",
"Salary": 78000
},
{
"EmpName": "Emp 03",
"Department": "Demo",
"Address": "Address03",
"Salary": 9999
},
{
"EmpName": "Emp 04",
"Department": "Demo",
"Address": "Address04",
"Salary": 9999
},
{
"EmpName": "Emp N",
"Department": "Demo",
"Address": "AddressN",
"Salary": 9999
}
]
}';
SELECT JSON_VALUE(#data, '$.Employees[0].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[0].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[0].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[0].Salary') AS 'Salary'
UNION ALL
SELECT JSON_VALUE(#data, '$.Employees[1].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[1].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[1].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[1].Salary') AS 'Salary'
UNION ALL
SELECT JSON_VALUE(#data, '$.Employees[2].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[2].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[2].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[2].Salary') AS 'Salary'
UNION ALL
SELECT JSON_VALUE(#data, '$.Employees[3].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[3].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[3].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[3].Salary') AS 'Salary'
UNION ALL
SELECT JSON_VALUE(#data, '$.Employees[N].EmpName') AS 'Name',
JSON_VALUE(#data, '$.Employees[N].Department') AS 'Department',
JSON_VALUE(#data, '$.Employees[N].Address') AS 'Address',
JSON_VALUE(#data, '$.Employees[N].Salary') AS 'Salary'
You could use OPENJSON and specify the schema using WITH something like this. The 'EmpName' column is read in from the JSON and renamed to 'Name'
select *
from openjson(#data, N'$.Employees')
with (Name nvarchar(200) N'strict $.EmpName',
Department nvarchar(20),
[Address] nvarchar(20),
Salary nvarchar(20));
Name Department Address Salary
Rohan Sharma IT 101, Sector 5, Gurug 100000
Manohar Lal Human Resources 17, Park Avenue, Mum 78000
Emp 03 Demo Address03 9999
Emp 04 Demo Address04 9999
Emp N Demo AddressN 9999
If you have JSON text's that stored in database table you can read or modify JSON values by using built in functions like
ISJSON (Transact-SQL) tests whether a string contains valid JSON.
JSON_VALUE (Transact-SQL) extracts a scalar value from a JSON string.
JSON_QUERY (Transact-SQL) extracts an object or an array from a JSON
string.
JSON_MODIFY (Transact-SQL) changes a value in a JSON string.
Below example will extract Empname and Department from JSonCol (column with JSON Value)
SELECT JSON_VALUE(jsonCol, '$.Employee.EmpName') AS Empname,
JSON_VALUE(jsonCol, '$.Employee.Deapartment') As Department
FROM Table_Name
Where ISJSON(JsonCol)>0;

Is there any way to set background-color by label in google chart?

I'm using react google timeline chart to display data.
I want label background like:
Thomas Jefferson -> red, George Washington -> Green, John Jay -> yellow, John Adams -> Orange
I'm using color option of the chart like:
options={{
colors: ['red', 'orange', 'yellow', 'green'],
}}
My chart code is like below:
<Chart
width={'100%'}
height={'400px'}
chartType="Timeline"
loader={<div>Loading Chart</div>}
data={[
[
{ type: 'string', id: 'Position' },
{ type: 'string', id: 'Name' },
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' },
],
[
'President',
'George Washington',
new Date(2019, 2, 4),
new Date(2019, 3, 30),
],
[
'President',
'Thomas Jefferson',
new Date(2019, 2, 4),
new Date(2019, 4, 4),
],
[
'Vice President',
'John Adams',
new Date(2019, 3, 21),
new Date(2019, 6, 4),
],
[
'Secretary of State',
'John Jay',
new Date(2019, 5, 4),
new Date(2019, 8, 20),
],
[
'President',
'John Adams',
new Date(2019, 2, 25),
new Date(2019, 8, 22),
],
[
'Vice President',
'George Washington',
new Date(2019, 7, 22),
new Date(2019, 11, 31),
],
]}
options={{
colors: ['red', 'orange', 'yellow', 'green'],
}}
rootProps={{ 'data-testid': '7' }}
/>
Can anyone help? Thanks in advance.
Here is the Solution what I found.
<Chart
width={'100%'}
height={'400px'}
chartType="Timeline"
loader={<div>Loading Chart</div>}
data={[
[
{ type: 'string', id: 'Position' },
{ type: 'string', id: 'Name' },
{ type: 'string', id: 'style', role: 'style' },
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' },
],
[
'President',
'George Washington',
'green'
new Date(2019, 2, 4),
new Date(2019, 3, 30),
],
[
'President',
'Thomas Jefferson',
'red',
new Date(2019, 2, 4),
new Date(2019, 4, 4),
],
[
'Vice President',
'John Adams',
'orange',
new Date(2019, 3, 21),
new Date(2019, 6, 4),
],
[
'Secretary of State',
'John Jay',
'yellow',
new Date(2019, 5, 4),
new Date(2019, 8, 20),
],
[
'President',
'John Adams',
'orange',
new Date(2019, 2, 25),
new Date(2019, 8, 22),
],
[
'Vice President',
'George Washington',
'green',
new Date(2019, 7, 22),
new Date(2019, 11, 31),
],
]}
rootProps={{ 'data-testid': '7' }}
/>
your color array sequence must be the same as your provide data array, first data name will take first color from colorArray.
import React from "react";
import ReactDOM from "react-dom";
import Chart from "react-google-charts";
class App extends React.Component {
getColors() {
let colorArray = [];
rows.forEach((item, index) => {
// logic to push color name in colorArray as as data index
})
return colorArray;
}
render() {
return (
<div className="App">
<Chart
width={"100%"}
height={"400px"}
chartType="Timeline"
loader={<div>Loading Chart</div>}
data={[
[
{ type: "string", id: "Position" },
{ type: "string", id: "Name" },
{ type: "date", id: "Start" },
{ type: "date", id: "End" }
],
[
"President",
"Thomas Jefferson",
new Date(2019, 2, 4),
new Date(2019, 5, 4)
],
[
"Vice President",
"John Adams",
new Date(2019, 3, 21),
new Date(2019, 6, 4)
],
[
"Secretary of State",
"John Jay",
new Date(2019, 5, 4),
new Date(2019, 8, 20)
],
[
"Vice President",
"George Washington",
new Date(2019, 7, 22),
new Date(2019, 11, 31)
]
]}
options={{
colors: this.getColors()
}}
rootProps={{ "data-testid": "7" }}
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Instead of color name use color code.
https://react-google-charts.com/timeline-chart#setting-individual-bar-colors
options = {{ colors: ['#FF0000', '#FFA500', '#FFFF00', '#00FF00'] }};

It's better to use array or object to store structured data?

Let's say there's a photo contest with categories and prizes data. We can store the data as an array or object. I'm just wondering which is better.
array example:
var contest = {
'name': 'Photo Contest',
'categories': [
{'name': 'landscape', 'type': 'single'},
{'name': 'portrait', 'type': 'single'},
{'name': 'food', 'type': 'single'},
],
'prizes': [
{'name': 'winner of the year', 'count': 1, 'cat': ''},
{'name': '1st', 'count': 1, 'cat': 'landscape'},
{'name': '2nd', 'count': 3, 'cat': 'landscape'},
{'name': '3rd', 'count': 5, 'cat': 'landscape'},
{'name': '1st', 'count': 1, 'cat': 'portrait'},
{'name': '2nd', 'count': 3, 'cat': 'portrait'},
{'name': '3rd', 'count': 5, 'cat': 'portrait'},
{'name': '1st', 'count': 1, 'cat': 'food'},
{'name': '2nd', 'count': 3, 'cat': 'food'},
{'name': '3rd', 'count': 5, 'cat': 'food'}
]
}
object example:
var contest = {
'name': 'Photo Contest',
'categories': {
'landscape': {'type': 'single'},
'portrait': {'type': 'single'},
'food': {'type': 'single'},
},
'prizes': {
'winner of the year': {'count': 1, 'cat': ''},
'landscape 1st': {'count': 1, 'cat': 'landscape'},
'landscape 2nd': {'count': 3, 'cat': 'landscape'},
'landscape 3rd': {'count': 5, 'cat': 'landscape'},
'portrait 1st': {'count': 1, 'cat': 'portrait'},
'portrait 2nd': {'count': 3, 'cat': 'portrait'},
'portrait 3rd': {'count': 5, 'cat': 'portrait'},
'food 1st': {'count': 1, 'cat': 'food'},
'food 2nd': {'count': 3, 'cat': 'food'},
'food 3rd': {'count': 5, 'cat': 'food'},
}
}
I'm making a general contests management system. Admin user can create a new contest by input some information(with different categories and prizes). The front-end page will get these info and display.
There're maybe other usages with these data, like record the winners(after the contest closed) or for searching.
It depends on the way you use those code afterwards.
If you want to use those objects afterwards for access functions go with creating classes and objects.
If this is for a small program just use an array.Don't bother with a classes or objects unless there's a need to. If you are writing a
small module in a larger application, and no other things need to
interface with your code, maybe an array is sufficient
Depends on what your intended use case is. If you want to display the results, it makes more sense to use an array. If you want to make a filter dialog which will let the user find only a particular subset of photos, use the object representation, since it better shows the underlying structure of the results.

Reference an element of an array using a variable in Actionscript 3

I have a bunch of arrays (Q001, Q002, Q003...). Each array is a question plus 4 possible answers. I want to randomly choose which question to display. So I randomly assign an array name to the variable chosenQuestion. Then I try to write the first element of that array into a text box, like so:
txt.Question.text = [chosenQuestion][0];
For example, if the the chosen question is Q001 then it puts Q001 in the text box. But I really want in the text box is the first element of the array Q001.
Supposed that you have your 3 arrays of questions, so to get the question, you can do like this :
var question_01:Array = ['question 01', 'answer 01', 'answer 02', 'answer 03', 'answer 04'];
var question_02:Array = ['question 02', 'answer 01', 'answer 02', 'answer 03', 'answer 04'];
var question_03:Array = ['question 03', 'answer 01', 'answer 02', 'answer 03', 'answer 04'];
var selected_question:int = Math.ceil(Math.random() * 3); // gives : 1, 2 or 3
trace(this['question_0' + selected_question][0]); // gives : question 01, for example
You can also put your questions arrays into an array like this :
var questions:Array = [
['question 01', 'answer 011', 'answer 02', 'answer 03', 'answer 04'],
['question 02', 'answer 012', 'answer 02', 'answer 03', 'answer 04'],
['question 03', 'answer 013', 'answer 02', 'answer 03', 'answer 04']
];
selected_question = Math.floor(Math.random() * 3); // gives : 0, 1 or 2
trace(questions[selected_question][0]); // gives : question 02, for example
Hope that can help.

Using Replace Strings to Match a User

I'm creating a small application that is supposed to create a leaderboard. I'm trying to match the users last name from the system.
The replace string is
var lastName = '{LastName}'
I would then like the application to match the replace string to the object in the users array that I created so that it shows their points at the top.
Here is the JSON:
$scope.users = [
{'firstName': 'Person', 'lastName': 'One', 'created': 15, 'replied': 13, 'read': 1151},
{'firstName': 'Person', 'lastName': 'Two', 'created': 13, 'replied': 24, 'read': 180},
{'firstName': 'Person', 'lastName': 'Three', 'created': 2, 'replied': 18, 'read': 157},
{'firstName': 'Person', 'lastName': 'Four', 'created': 12, 'replied': 7, 'read': 91},
{'firstName': 'Person', 'lastName': 'Five', 'created': 13, 'replied': 4, 'read': 153},
{'firstName': 'Person', 'lastName': 'Six', 'created': 12, 'replied': 2, 'read': 32},
{'firstName': 'Person', 'lastName': 'Seven', 'created': 10, 'replied': 1, 'read': 5},
{'firstName': 'Person', 'lastName': 'Eight', 'created': 9, 'replied': 0, 'read': 59},
{'firstName': 'Person', 'lastName': 'Nine', 'created': 0, 'replied': 1, 'read': 54},
{'firstName': 'Person', 'lastName': 'Ten', 'created': 0, 'replied': 0, 'read': 3},
{'firstName': 'Person', 'lastName': 'Eleven', 'created': 6, 'replied': 0, 'read': 10},
{'firstName': 'Person', 'lastName': 'Twelve', 'created': 15, 'replied': 0, 'read': 6},
{'firstName': 'Person', 'lastName': 'Thirteen', 'created': 0, 'replied': 0, 'read': 15},
{'firstName': 'Person', 'lastName': 'Fourteen', 'created': 2, 'replied': 7, 'read': 9},
{'firstName': 'Person', 'lastName': 'Fifteen', 'created': 10, 'replied': 1, 'read': 97},
{'firstName': 'Person', 'lastName': 'Sixteen', 'created': 18, 'replied': 14, 'read': 1087}
]
The application shows the top ten users in a list and is filtered from highest-to-lowest value for each point (created, replied and read).
How can I match the replace string of lastName with the object key lastName so that I can also show the user what their rank or point score is if they are not in the top ten?
Plunker is here: http://plnkr.co/edit/Nay1SeNjWcg30OLz73xI?p=preview
Thanks!
You can use filterFilter module, to filter your dict by a given attribute.
filterFilter($scope.users,{lastName: example_last_name});

Resources