With the help of #UnhandledExcepSean (Json pairs to rows) I was able to get an idea how to turn my json key/value pairs into rows. It was not as easy as I thought. However, I still have an issue. I was I was able to see how it can be done here:
I wanted it to look something like this:
+-----------+-------+------------+-----------+-------+------------------+---------+-----+-------+-------+---------+
| DateTime | Side | Identifier | Color | Level | SDSa | Current | LEF | Sys | Membr | SDS |
+-----------+-------+------------+-----------+-------+------------------+---------+-----+-------+-------+---------+
| 10/1/2018 | 15:01 | Left | 107604736 | Red | 0.65 5.053539157 | 0 | 0 | BOBJ7 | 5 | 1 |
| 10/2/2018 | 15:01 | Left | 107604737 | Red | 0.65 5.053539157 | 0.3035 | 1 | BOBJ8 | 6 | 0.98962 |
| 10/3/2018 | 15:01 | Left | 107604738 | Red | 0.65 5.053539157 | 0.6070 | 2 | BOBJ9 | 7 | 0.96576 |
+-----------+-------+------------+-----------+-------+------------------+---------+-----+-------+-------+---------+
I have found out how to manipulate the document when it is stored in a variable. I just cannot get find that balance or answer to how to use my same query for the json that is stored in a db in a column instead.
Here is an example of the document:
{
"DateTime": "10/1/2018 3:01:01 PM",
"Side": "Left",
"Identifier": "107604736",
"Color": "Red",
"Level": 0.65,
"SDSa": 5.0535391569137573,
"LEF": 0.0,
"System": "BOBJ7",
"Membrane": 5,
"Current": [
0.0,
0.303535521,
0.607071042,
0.910606563,
1.21414208,
1.51767755,
1.82121313,
2.12474871,
2.42828417,
2.73181963,
3.035355,
3.33889079,
3.64242625,
3.94596171,
4.24949741,
4.553033,
4.85656834,
5.160104,
5.46363926,
5.76717472,
6.07071,
6.374246,
6.67778158,
6.981317,
7.2848525,
7.588388,
7.89192343,
8.195459,
8.498995,
8.80253,
9.106066,
9.409601,
9.713137,
10.0166721,
10.3202076,
10.6237431,
10.9272785,
11.230814,
11.5343494,
11.8378849,
12.14142,
12.4449568,
12.7484922,
13.0520277,
13.3555632,
13.6590986,
13.9626341,
14.26617,
14.569705,
14.87324,
15.1767759,
15.4803114,
15.7838469,
16.0873833,
16.3909187,
16.6944542,
16.99799,
17.3015251,
17.60506,
17.908596,
18.2121315,
18.515667,
18.8192024,
19.1227379,
19.4262733,
19.7298088,
20.0333443,
20.33688,
20.6404152,
20.94395,
21.2474861,
21.5510216,
21.854557,
22.1580925,
22.461628,
22.7651634,
23.0686989,
23.3722343,
23.67577,
23.9793053,
24.28284,
24.5863781,
24.8899136,
25.193449,
25.4969845,
25.80052,
26.1040554,
26.40759,
26.7111263,
27.0146618,
27.3181973,
27.6217327,
27.9252682,
28.2288036,
28.53234,
28.8358746,
29.13941,
29.4429455,
29.74648,
30.0500164
],
"Measurements": [
{
"FPOS": 1,
"Orient": "H",
"SDS50": 6.8644590377807617,
"ImageN": 0,
"SDS": [
1.0,
0.9896224,
0.9657684,
0.937525332,
0.9123899,
0.888601959,
0.8634422,
0.8382806,
0.8161909,
0.7984247,
0.7806436,
0.7606637,
0.739305735,
0.720110357,
0.7029224,
0.6836812,
0.660055459,
0.6333771,
0.6086391,
0.5865341,
0.5649619,
0.540699542,
0.5150109,
0.4912444,
0.470531732,
0.4510031,
0.429589,
0.407328546,
0.386515945,
0.369066834,
0.353259325,
0.336980551,
0.3197548,
0.302164435,
0.2844041,
0.264812022,
0.2432023,
0.221351326,
0.203265771,
0.190894246,
0.183355331,
0.178263873,
0.17374523,
0.169159114,
0.1635048,
0.15626812,
0.148360759,
0.141854659,
0.1383282,
0.136285663,
0.133377567,
0.127650827,
0.119844966,
0.111289464,
0.103005029,
0.09480265,
0.0866060555,
0.07927561,
0.0740468055,
0.07167137,
0.07141984,
0.07215432,
0.07259899,
0.07151956,
0.0681445152,
0.06242689,
0.05562524,
0.0492420681,
0.04441181,
0.0410645567,
0.0388742052,
0.0380086526,
0.03860841,
0.04033492,
0.04170464,
0.04166763,
0.0399215743,
0.0370087326,
0.0335897,
0.0301406663,
0.02666917,
0.023069948,
0.0193837862,
0.0161479469,
0.0140230907,
0.0133305294,
0.0137383873,
0.0145777585,
0.0155265825,
0.0166243,
0.01805606,
0.01932042,
0.0196347721,
0.01826151,
0.0154753188,
0.012052347,
0.008844916,
0.00625393027,
0.004384732,
0.00334442779
],
"Processed": false
},
{
"FPOS": 2,
"Orient": "H",
"SDS50": 3.2426192760467529,
"ImageN": 0,
"SDS": [
1.0,
0.984369457,
0.940739632,
0.8834237,
0.8255927,
0.7736917,
0.7277459,
0.681687,
0.6329853,
0.582352459,
0.5328522,
0.48483035,
0.436798245,
0.388586164,
0.3424556,
0.302069068,
0.267472,
0.237092659,
0.209047124,
0.184123,
0.163114548,
0.144511625,
0.126265839,
0.107269846,
0.08942619,
0.07420107,
0.06193066,
0.0517099164,
0.0435060449,
0.0383287631,
0.0352067538,
0.03245497,
0.0286534447,
0.0242379941,
0.0201460086,
0.016266821,
0.0121985339,
0.008013846,
0.00560544431,
0.00502379332,
0.004533774,
0.004487538,
0.00551742641,
0.007546712,
0.009179788,
0.009129186,
0.007475236,
0.005305866,
0.004060863,
0.00462530646,
0.00631512143,
0.00748074846,
0.007632819,
0.006844715,
0.00562061928,
0.005166012,
0.006103046,
0.00768285431,
0.009006567,
0.009526576,
0.009514096,
0.009059127,
0.008065625,
0.006526997,
0.00434135273,
0.00191119267,
0.00254829624,
0.006861757,
0.0108742379,
0.0131905386,
0.013858974,
0.0132871456,
0.012235119,
0.01142512,
0.01094334,
0.0107232835,
0.0107062105,
0.010995524,
0.0112270387,
0.0102753676,
0.00612402242,
0.0010008571,
0.00318561238,
0.009038351,
0.0119382814,
0.0132263815,
0.013723935,
0.0133564435,
0.0129926438,
0.0127558094,
0.011888911,
0.009955382,
0.00670363754,
0.00246145763,
0.000897339836,
0.0037357898,
0.006457583,
0.007566943,
0.007532189,
0.006015837
],
"Processed": false
}}
You JSON-object has some easy to query values in the first level.
Furthermore, there is an array of values called Current, and there is more: There is an object called Measurements, which is an array of objects by its own. And still there is more: The objects within Measurements contain an array of values themselves, called SDS.
Assumably you won't be happy with a flat give-me-everything query. This would lead to very many rows with repeating columns all over...
Try it out (I create a mockup-table to simulate your needs):
DECLARE #mockupTable TABLE (ID INT IDENTITY,YourJson NVARCHAR(MAX));
INSERT INTO #mockupTable VALUES
(N'{
"DateTime": "10/1/2018 3:01:01 PM",
"Side": "Left",
"Identifier": "107604736",
"Color": "Red",
"Level": 0.65,
"SDSa": 5.0535391569137573,
"LEF": 0.0,
"System": "BOBJ7",
"Membrane": 5,
"Current": [
0.0,
0.303535521,
0.607071042,
0.910606563,
1.21414208,
1.51767755,
1.82121313,
2.12474871,
2.42828417,
2.73181963,
3.035355,
3.33889079,
3.64242625,
3.94596171,
4.24949741,
4.553033,
4.85656834,
5.160104,
5.46363926,
5.76717472,
6.07071,
6.374246,
6.67778158,
6.981317,
7.2848525,
7.588388,
7.89192343,
8.195459,
8.498995,
8.80253,
9.106066,
9.409601,
9.713137,
10.0166721,
10.3202076,
10.6237431,
10.9272785,
11.230814,
11.5343494,
11.8378849,
12.14142,
12.4449568,
12.7484922,
13.0520277,
13.3555632,
13.6590986,
13.9626341,
14.26617,
14.569705,
14.87324,
15.1767759,
15.4803114,
15.7838469,
16.0873833,
16.3909187,
16.6944542,
16.99799,
17.3015251,
17.60506,
17.908596,
18.2121315,
18.515667,
18.8192024,
19.1227379,
19.4262733,
19.7298088,
20.0333443,
20.33688,
20.6404152,
20.94395,
21.2474861,
21.5510216,
21.854557,
22.1580925,
22.461628,
22.7651634,
23.0686989,
23.3722343,
23.67577,
23.9793053,
24.28284,
24.5863781,
24.8899136,
25.193449,
25.4969845,
25.80052,
26.1040554,
26.40759,
26.7111263,
27.0146618,
27.3181973,
27.6217327,
27.9252682,
28.2288036,
28.53234,
28.8358746,
29.13941,
29.4429455,
29.74648,
30.0500164
],
"Measurements": [
{
"FPOS": 1,
"Orient": "H",
"SDS50": 6.8644590377807617,
"ImageN": 0,
"SDS": [
1.0,
0.9896224,
0.9657684,
0.937525332,
0.9123899,
0.888601959,
0.8634422,
0.8382806,
0.8161909,
0.7984247,
0.7806436,
0.7606637,
0.739305735,
0.720110357,
0.7029224,
0.6836812,
0.660055459,
0.6333771,
0.6086391,
0.5865341,
0.5649619,
0.540699542,
0.5150109,
0.4912444,
0.470531732,
0.4510031,
0.429589,
0.407328546,
0.386515945,
0.369066834,
0.353259325,
0.336980551,
0.3197548,
0.302164435,
0.2844041,
0.264812022,
0.2432023,
0.221351326,
0.203265771,
0.190894246,
0.183355331,
0.178263873,
0.17374523,
0.169159114,
0.1635048,
0.15626812,
0.148360759,
0.141854659,
0.1383282,
0.136285663,
0.133377567,
0.127650827,
0.119844966,
0.111289464,
0.103005029,
0.09480265,
0.0866060555,
0.07927561,
0.0740468055,
0.07167137,
0.07141984,
0.07215432,
0.07259899,
0.07151956,
0.0681445152,
0.06242689,
0.05562524,
0.0492420681,
0.04441181,
0.0410645567,
0.0388742052,
0.0380086526,
0.03860841,
0.04033492,
0.04170464,
0.04166763,
0.0399215743,
0.0370087326,
0.0335897,
0.0301406663,
0.02666917,
0.023069948,
0.0193837862,
0.0161479469,
0.0140230907,
0.0133305294,
0.0137383873,
0.0145777585,
0.0155265825,
0.0166243,
0.01805606,
0.01932042,
0.0196347721,
0.01826151,
0.0154753188,
0.012052347,
0.008844916,
0.00625393027,
0.004384732,
0.00334442779
],
"Processed": false
},
{
"FPOS": 2,
"Orient": "H",
"SDS50": 3.2426192760467529,
"ImageN": 0,
"SDS": [
1.0,
0.984369457,
0.940739632,
0.8834237,
0.8255927,
0.7736917,
0.7277459,
0.681687,
0.6329853,
0.582352459,
0.5328522,
0.48483035,
0.436798245,
0.388586164,
0.3424556,
0.302069068,
0.267472,
0.237092659,
0.209047124,
0.184123,
0.163114548,
0.144511625,
0.126265839,
0.107269846,
0.08942619,
0.07420107,
0.06193066,
0.0517099164,
0.0435060449,
0.0383287631,
0.0352067538,
0.03245497,
0.0286534447,
0.0242379941,
0.0201460086,
0.016266821,
0.0121985339,
0.008013846,
0.00560544431,
0.00502379332,
0.004533774,
0.004487538,
0.00551742641,
0.007546712,
0.009179788,
0.009129186,
0.007475236,
0.005305866,
0.004060863,
0.00462530646,
0.00631512143,
0.00748074846,
0.007632819,
0.006844715,
0.00562061928,
0.005166012,
0.006103046,
0.00768285431,
0.009006567,
0.009526576,
0.009514096,
0.009059127,
0.008065625,
0.006526997,
0.00434135273,
0.00191119267,
0.00254829624,
0.006861757,
0.0108742379,
0.0131905386,
0.013858974,
0.0132871456,
0.012235119,
0.01142512,
0.01094334,
0.0107232835,
0.0107062105,
0.010995524,
0.0112270387,
0.0102753676,
0.00612402242,
0.0010008571,
0.00318561238,
0.009038351,
0.0119382814,
0.0132263815,
0.013723935,
0.0133564435,
0.0129926438,
0.0127558094,
0.011888911,
0.009955382,
0.00670363754,
0.00246145763,
0.000897339836,
0.0037357898,
0.006457583,
0.007566943,
0.007532189,
0.006015837
],
"Processed": false}
]}');
--This is the query to get all first level elements
SELECT ID
,A.*
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson) A
WHERE ID=1;
--But there is the WITH-clause, which allows you to transform this list of columns to a single result row with typed columns:
SELECT ID
,A.*
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson)
WITH
(
DateTime DATETIME N'$.DateTime'
,Side NVARCHAR(50) N'$.Side'
--add all variables of the first level
,Membrane INT N'$.Membrane'
) A
WHERE ID=1;
--With this we grab into the values of current:
SELECT ID
,A.*
,C.*
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson)
WITH
(
DateTime DATETIME N'$.DateTime'
,Side NVARCHAR(50) N'$.Side'
--add all variables of the first level
,Membrane INT N'$.Membrane'
) A
CROSS APPLY OPENJSON(YourJson,'$.Current') C
WHERE ID=1;
--And the next query allows as to get the first-level-elements of the two objects within Measurement:
SELECT ID
,A.*
,M.*
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson)
WITH
(
DateTime DATETIME N'$.DateTime'
,Side NVARCHAR(50) N'$.Side'
--add all variables of the first level
,Membrane INT N'$.Membrane'
) A
CROSS APPLY OPENJSON(YourJson,'$.Measurements')
WITH
(
FPOS INT N'$.FPOS'
,Orient VARCHAR(10) N'$.Orient'
--Add more
) M
WHERE ID=1;
--And this last query will return the two Measurements with all values in SDS. (Look at the AS JSON within the WITH-clause!):
SELECT ID
,A.*
,M.*
,V.*
FROM #mockupTable
CROSS APPLY OPENJSON(YourJson)
WITH
(
DateTime DATETIME N'$.DateTime'
,Side NVARCHAR(50) N'$.Side'
--add all variables of the first level
,Membrane INT N'$.Membrane'
) A
CROSS APPLY OPENJSON(YourJson,'$.Measurements')
WITH
(
FPOS INT N'$.FPOS'
,Orient NVARCHAR(10) N'$.Orient'
--Add more
,[SDS] NVARCHAR(MAX) AS JSON --allows to return the JSON reflecting the array
) M
CROSS APPLY OPENJSON(M.SDS) V
WHERE ID=1;
Now you know how to fetch everything. What you are going to do with this is up to you...
Related
This is as example taken from another thread, but essentially I would like to achieve this:
Sample data
ID Name Value
1 TV1 {"URL": "www.url.com", "Icon": "some_icon"}
2 TV2 {"URL": "www.url.com", "Icon": "some_icon", "Facebook": "Facebook_URL"}
3 TV3 {"URL": "www.url.com", "Icon": "some_icon", "Twitter": "Twitter_URL"}
..........
Expected output
ID Name URL Icon Facebook Twitter
1 TV1 www.url.com some_icon NULL NULL
2 TV2 www.url.com some_icon Facebook_URL NULL
3 TV3 www.url.com some_icon NULL Twitter_URL
I'm totally new to Snowflake so I'm shaking my head on how to do this easily (and hopefully automatically, in the case where some rows might have more elements in the json than other rows, which would be tedious to assign manually). Some lines might have sub-categories too.
I found the parse_json function for Snowflake, but it's only giving me the same json column in a new column, still in json format.
TIA!
You can create a view over your table with the following SELECT:
SELECT ID,
Name,
Value:URL::varchar as URL,
Value:Icon::varchar as Icon,
Value:Facebook::varchar as Facebook,
Value:Twitter::varchar as Twitter
FROM tablename;
Additional attributes will be ignored unless you add them to the view. There is no way to "automatically" include them into the view, but you could create a stored procedure that dynamically generates the view based on all the attributes that are in the full variant content of a table.
You can create a SP to automatically build the CREATE VIEW for you based on the JSON data in the VARIANT.
I have some simple example below:
-- prepare the table and data
create or replace table test (
col1 int, col2 string,
data1 variant, data2 variant
);
insert into test select 1,2, parse_json(
'{"URL": "test", "Icon": "test1", "Facebook": "http://www.facebook.com"}'
), parse_json(
'{"k1": "test", "k2": "test1", "k3": "http://www.facebook.com"}'
);
insert into test select 3,4,parse_json(
'{"URL": "test", "Icon": "test1", "Twitter": "http://www.twitter.com"}'
), parse_json(
'{"k4": "v4", "k3": "http://www.ericlin.me"}'
);
-- create the SP, we need to know which table and
-- column has the variant data
create or replace procedure create_view(
table_name varchar
)
returns string
language javascript
as
$$
var final_columns = [];
// first, find out the columns
var query = `SHOW COLUMNS IN TABLE ${TABLE_NAME}`;
var stmt = snowflake.createStatement({sqlText: query});
var result = stmt.execute();
var variant_columns = [];
while (result.next()) {
var col_name = result.getColumnValue(3);
var data_type = JSON.parse(result.getColumnValue(4));
// just use it if it is not a VARIANT type
// if it is variant type, we need to remember this column
// and then run query against it later
if (data_type["type"] != "VARIANT") {
final_columns.push(col_name);
} else {
variant_columns.push(col_name);
}
}
var columns = {};
query = `SELECT ` + variant_columns.join(', ') + ` FROM ${TABLE_NAME}`;
stmt = snowflake.createStatement({sqlText: query});
result = stmt.execute();
while (result.next()) {
for(i=1; i<=variant_columns.length; i++) {
var sub_result = result.getColumnValue(i);
if(!sub_result) {
continue;
}
var keys = Object.keys(sub_result);
for(j=0; j<keys.length; j++) {
columns[variant_columns[i-1] + ":" + keys[j]] = keys[j];
}
}
}
for(path in columns) {
final_columns.push(path + "::STRING AS " + columns[path]);
}
var create_view_sql = "CREATE OR REPLACE VIEW " +
TABLE_NAME + "_VIEW\n" +
"AS SELECT " + "\n" +
" " + final_columns.join(",\n ") + "\n" +
"FROM " + TABLE_NAME + ";";
snowflake.execute({sqlText: create_view_sql});
return create_view_sql + "\n\nVIEW created successfully.";
$$;
Execute the SP will return below string:
call create_view('TEST');
+---------------------------------------+
| CREATE_VIEW |
|---------------------------------------|
| CREATE OR REPLACE VIEW TEST_VIEW |
| AS SELECT |
| COL1, |
| COL2, |
| DATA1:Facebook::STRING AS Facebook, |
| DATA1:Icon::STRING AS Icon, |
| DATA1:URL::STRING AS URL, |
| DATA2:k1::STRING AS k1, |
| DATA2:k2::STRING AS k2, |
| DATA2:k3::STRING AS k3, |
| DATA1:Twitter::STRING AS Twitter, |
| DATA2:k4::STRING AS k4 |
| FROM TEST; |
| |
| VIEW created successfully. |
+---------------------------------------+
Then query the VIEW:
SELECT * FROM TEST_VIEW;
+------+------+-------------------------+-------+------+------+-------+-------------------------+------------------------+------+
| COL1 | COL2 | FACEBOOK | ICON | URL | K1 | K2 | K3 | TWITTER | K4 |
|------+------+-------------------------+-------+------+------+-------+-------------------------+------------------------+------|
| 1 | 2 | http://www.facebook.com | test1 | test | test | test1 | http://www.facebook.com | NULL | NULL |
| 3 | 4 | NULL | test1 | test | NULL | NULL | http://www.ericlin.me | http://www.twitter.com | v4 |
+------+------+-------------------------+-------+------+------+-------+-------------------------+------------------------+------+
Query the source table:
SELECT * FROM TEST;
+------+------+------------------------------------------+-----------------------------------+
| COL1 | COL2 | DATA1 | DATA2 |
|------+------+------------------------------------------+-----------------------------------|
| 1 | 2 | { | { |
| | | "Facebook": "http://www.facebook.com", | "k1": "test", |
| | | "Icon": "test1", | "k2": "test1", |
| | | "URL": "test" | "k3": "http://www.facebook.com" |
| | | } | } |
| 3 | 4 | { | { |
| | | "Icon": "test1", | "k3": "http://www.ericlin.me", |
| | | "Twitter": "http://www.twitter.com", | "k4": "v4" |
| | | "URL": "test" | } |
| | | } | |
+------+------+------------------------------------------+-----------------------------------+
You can refine this SP to detect nested data and have them added to the columns list as well.
I have incoming json structure like
{
"type":1,
"location":[
{"lattitude":"0", "longitude":"0"},
{"lattitude":"0", "longitude":"0"},
{"lattitude":"0", "longitude":"0"}]
}
I need to insert this into a database like
|------|-----------|-----------|
| type | lattitude | longitude |
|------|-----------|-----------|
| 1 | 0 | 0 |
|------|-----------|-----------|
| 1 | 0 | 0 |
|------|-----------|-----------|
| 1 | 0 | 0 |
|------|-----------|-----------|
how do I parse the json and build an sql query?
If you want to use Postgres solution, you may do
--INSERT INTO yourtab( type,lattitude,longitude)
select jsoncol->>'type' , j->>'lattitude'
j->>'longitude'
from
( values (:yourjsonstr :: jsonb ) ) as t(jsoncol) cross join
lateral jsonb_array_elements(jsoncol->'location')
as j;
DEMO
You can use json-sql
Example:
var sql = jsonSql.build({
type: 'insert',
table: 'users',
values: {
name: 'John',
lastname: 'Snow',
age: 24,
gender: 'male'
}
});
sql.query
// insert into users (name, lastname, age, gender) values ($p1, $p2, 24, $p3);
sql.values
// { p1: 'John', p2: 'Snow', p3: 'male' }
See the documentation: https://www.npmjs.com/package/json-sql
I'm struggling to structure JSON using SQL.
Say I have a table like this:
| col1 | col2 | col3 |
+---------------+----------+----------+
| specialvalue | someval | someval |
| specialvalue2 | someval2 | someval2 |
| | | |
I'm trying to get a structure like the following:
{
"specialvalue": {
"specialcol": "specialvalue",
"col2": "someval",
"col3": "someval"
},
"specialvalue2": {
"specialcol": "specialvalue2",
"col2": "someval2",
"col3": "someval2"
}
}
How can I accomplish this? Can I use JSON_MODIFY with dynamic keys, while mapping through every row in the set?
The closest I've gotten is the following:
SELECT
specialcol,
col2,
col3
INTO #tmpTbl
FROM myTable
SELECT
specialcol,
(SELECT * FROM #tmpTbl FOR JSON AUTO) as 'Value'
FROM #tmpTbl
FOR JSON AUTO
DROP TABLE #tmp
Which returns the following:
{
"specialcol":"specialvalue",
"Value":{
"col1": "specialvalue",
"col2": "someval",
"col3": "someval"
},
"specialcol":"specialvalue2",
"Value":{
"col1": "specialvalue2",
"col2": "someval2",
"col3": "someval2"
}
}
Which is close, but not quite what I need.
Is there a way to use JSON_MODIFY to accomplish what I'm trying to get?
From my comment and thinking about this. Not the most elegant, but could potential get you there.
Inline query to get the results in json, then wrap those results based on the value from your col1 as the key. Put it all together comma delimited and then a final wrap in brackets.
DECLARE #TestData TABLE
(
[col1] NVARCHAR(100)
, [col2] NVARCHAR(100)
, [col3] NVARCHAR(100)
);
DECLARE #JsonValue NVARCHAR(MAX) = '';
INSERT INTO #TestData (
[col1]
, [col2]
, [col3]
)
VALUES ( 'specialvalue', 'someval', 'someval' )
, ( 'specialvalue2', 'someval2', 'someval2' );
SELECT #JsonValue = #JsonValue + N'"' + [a].[col1] + N'": '
+ (
SELECT [aa].[col1] AS 'specialvalue'
, [aa].[col2] AS 'col2'
, [aa].[col3] AS 'col3'
FROM #TestData [aa]
WHERE [aa].[col1] = [a].[col1]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) + N','
FROM #TestData [a];
SET #JsonValue = N'{' + SUBSTRING(#JsonValue, 1, LEN(#JsonValue) - 1) + N'}';
SELECT #JsonValue;
Gets you this:
{
"specialvalue": {
"specialvalue": "specialvalue",
"col2": "someval",
"col3": "someval"
},
"specialvalue2": {
"specialvalue": "specialvalue2",
"col2": "someval2",
"col3": "someval2"
}
}
SQL Server 2017 -
;WITH cte as (
select 'specialvalue' as specialcol, 'someval' col2, 'someval' col3 union
select 'specialvalue2' as specialcol, 'someval2' col2, 'someval2' col3 )
SELECT
CASE WHEN specialcol = 'specialvalue' THEN specialcol END as [specialvalue.specialcol],
CASE WHEN specialcol = 'specialvalue' THEN col2 END as [specialvalue.col2],
CASE WHEN specialcol = 'specialvalue' THEN col3 END as [specialvalue.col3],
CASE WHEN specialcol = 'specialvalue2' THEN specialcol END as [specialvalue2.specialcol],
CASE WHEN specialcol = 'specialvalue2' THEN col2 END as [specialvalue2.col2],
CASE WHEN specialcol = 'specialvalue2' THEN col3 END as [specialvalue2.col3]
FROM cte
FOR JSON PATH
Output:
{
"specialvalue":{
"specialcol":"specialvalue",
"col2":"someval",
"col3":"someval"
}
},
{
"specialvalue2":{
"specialcol":"specialvalue2",
"col2":"someval2",
"col3":"someval2"
}
}
I was thrown in a new project, which is apparently more than just oudated. The application saves opening hours in a very weird pattern in the DB and this is driving me crazy for over a week now.
Please have a look at this image:
As you might see, the opening hours are saved in a pattern like:
dayFrom | dayTo | timeFrom | timeTo
=======================================
monday | friday | 07:00 | 17:00
saturday | | 08:00 | 12:00
Just to prevent any misunderstanding:
Open MO - FR from 07:00 to 17:00
Open SA from 08:00 to 12:00
Closed on Sunday
Now, this seems to be kinda off already, but sticking with that, a table could look like this:
dayFrom | dayTo | timeFrom | timeTo
=======================================
monday | tuesday | 07:00 | 14:00
wednesday | | 08:00 | 12:00
thursday | friday | 07:30 | 13:00
saturday | | 08:00 | 12:00
So, now my problem: I need to make a loop (or something like this) to create a valid json-string, containing all these opening hours.
Right now, I have this:
jsonAppendix = "{""openingHours"":["
for i = 1 To cint(hoechsterTag)
jsonAppendix = jsonAppendix & "{""dayOfWeek"":" & i & ", ""from1"":""" & rs("ZeitVon") & """, ""to1"":""" & rs("ZeitBis") & """},"
next
'Remove last comma
jsonAppendix = LEFT(jsonAppendix, (LEN(jsonAppendix)-1))
jsonAppendix = jsonAppendix & "]}"
If I have only a "monday-friday", it works already, but the 2nd (or next entries) aren't taken into account.
The output looks like this, which is apparently kinda correct:
{
"openingHours":[
{
"dayOfWeek":1,
"from1":"07:00",
"to1":"17:00"
},
{
"dayOfWeek":2,
"from1":"07:00",
"to1":"17:00"
},
{
"dayOfWeek":3,
"from1":"07:00",
"to1":"17:00"
},
{
"dayOfWeek":4,
"from1":"07:00",
"to1":"17:00"
},
{
"dayOfWeek":5,
"from1":"07:00",
"to1":"17:00"
}
]
}
But the "Saturday" is not being recognized.
My function looks like this:
SQL = "SELECT * FROM StandortOpen WHERE S_ID = " & iStandortId & " AND OpenArt = '" & sArt & "' ORDER BY Sort,OpenArt DESC"
call openRS(SQL)
'day-mapping
tageV(0) = replace(rs("TagVon"),"Mo", 1)
tageV(1) = replace(rs("TagVon"),"Di", 2)
tageV(2) = replace(rs("TagVon"),"Mi", 3)
tageV(3) = replace(rs("TagVon"),"Do", 4)
tageV(4) = replace(rs("TagVon"),"Fr", 5)
tageV(5) = replace(rs("TagVon"),"Sa", 6)
tageV(6) = 7
tageB(0) = replace(rs("TagBis"),"Mo", 1)
tageB(1) = replace(rs("TagBis"),"Di", 2)
tageB(2) = replace(rs("TagBis"),"Mi", 3)
tageB(3) = replace(rs("TagBis"),"Do", 4)
tageB(4) = replace(rs("TagBis"),"Fr", 5)
tageB(5) = replace(rs("TagBis"),"Sa", 6)
'for example: mo - fr
for each item in tageV
'save smallest weekday
if(isNumeric(item) AND item > "") then
if(cint(item) <= cint(niedrigsterTag)) then
niedrigsterTag = cint(item)
end if
end if
next
for each item in tageB
'save highest weekday
if(isNumeric(item) AND item > "") then
if(cint(item) >= cint(hoechsterTag)) then
hoechsterTag = cint(item)
end if
end if
next
And the openRS()-Function:
sub openRS(str_sql)
'Response.write "SQL: " & str_sql & "<br>"
set rs = CreateObject("ADODB.Recordset")
rs.open str_sql,conn,1,3
end sub
So basically: Mapping numbers to the days, iterating through (or compare them to get a timespan).
I'm using a RecordSet as well. Maybe I need to use arrays or something like this? Any help would be really appreciated.
I can't alter the table nor the design of that, I have to stick with that gargabe
If you want to create the dataset in SQL Server, consider the following
Example
Declare #YourTable table (dayFrom varchar(25),dayTo varchar(25),timeFrom varchar(25),timeTo varchar(25))
Insert Into #YourTable values
('monday' ,'tuesday','07:00','14:00'),
('wednesday','' ,'08:00','12:00'),
('thursday' ,'friday' ,'07:30','13:00'),
('saturday' ,'' ,'08:00','12:00')
;with cteD as (Select * From (Values(1,'Monday'),(2,'Tuesday'),(3,'Wednesday'),(4,'Thursday'),(5,'Friday'),(6,'Saturday'),(7,'Sunday')) DDD(DD,DDD) ),
cteR as (
Select A.*
,R1 = B.DD
,R2 = IsNull(C.DD,B.DD)
From #YourTable A
Left Join cteD B on dayFrom = B.DDD
Left Join cteD C on dayTo = C.DDD
Where 1=1 -- Your WHERE STATEMENT HERE
)
Select daySeq = A.DD
,dayOfWeek = A.DDD
,from1 = IsNull(B.TimeFrom,'Closed')
,from2 = IsNull(B.TimeTo,'Closed')
From cteD A
Left Join cteR B on A.DD between B.R1 and B.R2
Order By 1
Returns
Note: The Closed is Optional. Remove the "LEFT" Join in the final query
Now, if you want to create the JSON String in SQL Server, and you're NOT on 2016, we can tweak the final query and add a UDF.
Select JSON=[dbo].[udf-Str-JSON](0,0,(
Select daySeq = A.DD
,dayOfWeek = A.DDD
,from1 = IsNull(B.TimeFrom,'Closed')
,from2 = IsNull(B.TimeTo,'Closed')
From cteD A
Left Join cteR B on A.DD between B.R1 and B.R2
Order By 1
For XML RAW
))
Returned JSON String
[{
"daySeq": "1",
"dayOfWeek": "Monday",
"from1": "07:00",
"from2": "14:00"
}, {
"daySeq": "2",
"dayOfWeek": "Tuesday",
"from1": "07:00",
"from2": "14:00"
}, {
"daySeq": "3",
"dayOfWeek": "Wednesday",
"from1": "08:00",
"from2": "12:00"
}, {
"daySeq": "4",
"dayOfWeek": "Thursday",
"from1": "07:30",
"from2": "13:00"
}, {
"daySeq": "5",
"dayOfWeek": "Friday",
"from1": "07:30",
"from2": "13:00"
}, {
"daySeq": "6",
"dayOfWeek": "Saturday",
"from1": "08:00",
"from2": "12:00"
}, {
"daySeq": "7",
"dayOfWeek": "Sunday",
"from1": "Closed",
"from2": "Closed"
}]
The UDF if Interested
CREATE FUNCTION [dbo].[udf-Str-JSON] (#IncludeHead int,#ToLowerCase int,#XML xml)
Returns varchar(max)
AS
Begin
Declare #Head varchar(max) = '',#JSON varchar(max) = ''
; with cteEAV as (Select RowNr =Row_Number() over (Order By (Select NULL))
,Entity = xRow.value('#*[1]','varchar(100)')
,Attribute = xAtt.value('local-name(.)','varchar(100)')
,Value = xAtt.value('.','varchar(max)')
From #XML.nodes('/row') As R(xRow)
Cross Apply R.xRow.nodes('./#*') As A(xAtt) )
,cteSum as (Select Records=count(Distinct Entity)
,Head = IIF(#IncludeHead=0,IIF(count(Distinct Entity)<=1,'[getResults]','[[getResults]]'),Concat('{"status":{"successful":"true","timestamp":"',Format(GetUTCDate(),'yyyy-MM-dd hh:mm:ss '),'GMT','","rows":"',count(Distinct Entity),'"},"retults":[[getResults]]}') )
From cteEAV)
,cteBld as (Select *
,NewRow=IIF(Lag(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,'',',{')
,EndRow=IIF(Lead(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,',','}')
,JSON=Concat('"',IIF(#ToLowerCase=1,Lower(Attribute),Attribute),'":','"',Value,'"')
From cteEAV )
Select #JSON = #JSON+NewRow+JSON+EndRow,#Head = Head From cteBld, cteSum
Return Replace(#Head,'[getResults]',Stuff(#JSON,1,1,''))
End
-- Parameter 1: #IncludeHead 1/0
-- Parameter 2: #ToLowerCase 1/0 (converts field name to lowercase
-- Parameter 3: (Select * From ... for XML RAW)
-- Syntax : Select [dbo].[udf-Str-JSON](0,1,(Select Top 2 RN=Row_Number() over (Order By (Select NULL)),* from [Chinrus-Shared].[dbo].[ZipCodes] Where StateCode in ('RI') for XML RAW))
/*
Declare #User table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #User values
(1,1,'John','Smith','john.smith#email.com'),(2,0,'Jane','Doe' ,'jane.doe#email.com')
Declare #XML xml = (Select * from #User for XML RAW)
Select A.ID
,B.JSON
From #User A
Cross Apply (Select JSON=[dbo].[udf-Str-JSON](0,0,(Select A.* For XML Raw)) ) B
*/
I'm in the middle of converting an NTEXT column into multiple records. I'm looking to split the original column by new line or json object. It's a unique scenario, to be sure, but outside of a sql environment this regex correctly matches everything I need from the original column:
({(.*)(.*\r\n)*?})|(.+\r\n).
If I have a record with a column that has the value:
Foo bar baz
hello world
{
foo: 'bar',
bar: 'foo'
}
{
foo: 'foo',
bar: 'bar'
}
I want to break it into multiple records:
| ID | Text |
---------------------
| 1 | Foo bar baz |
| 2 | hello world |
| 3 | { |
| | foo: 'bar' |
| | bar: 'foo' |
| | } |
| 4 | { |
| | foo: 'foo' |
| | bar: 'bar' |
| | } |
Any easy way to accomplish this? It's a SQL Express server.
With the help of a split/parse function
Declare #String varchar(max)='Foo bar baz
hello world
{
foo: ''bar'',
bar: ''foo''
}
{
foo: ''foo'',
bar: ''bar''
}'
Select ID=Row_Number() over (Order By (Select NULL))
,Text = B.RetVal
From (Select RetSeq,RetVal = IIF(CharIndex('}',RetVal)>0,'{'+RetVal,RetVal) from [dbo].[udf-Str-Parse](#String,'{')) A
Cross Apply (
Select * from [dbo].[udf-Str-Parse](A.RetVal,IIF(CharIndex('{',A.RetVal)>0,char(1),char(10)))
) B
Where B.RetVal is Not Null
Returns
ID Text
1 Foo bar baz
2 hello world
3 {
foo: 'bar',
bar: 'foo'
}
4 {
foo: 'foo',
bar: 'bar'
}
The UDF if needed
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>'+ Replace(#String,#Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--Performance On a 5,000 random sample -8K 77.8ms, -1M 79ms (+1.16), -- 91.66ms (+13.8)