I have a table that looks like this:
And the JSON has dynamic keys and looks like this:
{
key_1:{
value_1:a
value_2:b
},
key_2:{
value_1:c
value_2:d
}
}
I need to parse this table to get an output that looks like this:
Tried it with JS functions but couldn't get it quite right.
Thanks in advance! :)
Consider below approach
create temp function get_keys(input string) returns array<string> language js as """
return Object.keys(JSON.parse(input));
""";
create temp function get_values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));
""";
create temp function get_leaves(input string) returns string language js as '''
function flattenObj(obj, parent = '', res = {}){
for(let key in obj){
let propName = parent ? parent + '.' + key : key;
if(typeof obj[key] == 'object'){
flattenObj(obj[key], propName, res);
} else {
res[propName] = obj[key];
}
}
return JSON.stringify(res);
}
return flattenObj(JSON.parse(input));
''';
create temp table temp as (
select format('%t', t) row_id, date, name, val,
split(key, '.')[offset(0)] as key,
split(key, '.')[offset(1)] as col,
from your_table t, unnest([struct(get_leaves(json_extract(json, '$')) as leaves)]),
unnest(get_keys(leaves)) key with offset
join unnest(get_values(leaves)) val with offset using(offset)
);
execute immediate (
select '''
select * except(row_id) from temp
pivot (any_value(val) for col in ("''' || string_agg(distinct col, '","') || '"))'
from temp
);
if applied to sample data in your question - output is
Related
I have a stored proc where I construct the JSON with the values and I want to pass this in to child procs and update the same JSOn variable and return it back.
CREATE OR REPLACE PROC1()
RETURNS STRING
LANGUAGE JavaScript
AS
'
--Some functions and constants
function execSqlSingleValue(sql_text){
exec_result = snowflake.execute({sqlText:sql_text});
exec_result.next();
return exec_result.getColumnValue(1);
}
const column1 = `ABC`;
const column2 = `DEF`;
const column3 = `GHL`;
var v1_json = {
col1: column1,
col2: column2,
col3: column3,
col4: `NONE`,
col5: 0,
}
try{
return execSqlSingleValue(`CALL PROC2(\'${v1_json}\')`);
}
catch(err){
return JSON.stringify(v1_json);
}
'
;
CREATE OR REPLACE PROCEDURE PROC2(v1_json VARIANT)
RETURNS STRING
LANGUAGE JavaScript
AS
'
const column4 = XYZ; -- Some other calculation
const column5 = MMM; -- Some other calculation
v1_json.col4 = `${column4}`;
v1_json.col5 = `${column5}`;
return JSON.stringify(v1_json);
'
;
I have tried to do it with VARIANT and VARCHAR , but could not succeed.How do we achieve this ?
Have you tried to convert it to a string and then convert JSON in the child procedure?
snowflake.execute(
{
sqlText: "call PROC2(?);",
binds:[ JSON.stringify(v1_json) ]
}
In the child procedure (v1_json is defined as a varchar parameter):
var json_obj = JSON.parse(v1_json)
I have the following JSON List: '["Foo","Bar"]'
The following entries are in my MySQL table t
Name | Color
--------------
Foo | Red
Bar | Blue
Foobar | Green
Is there a way to use my JSON List as a condition in my where clause and get the same result like:
select * from t where name in ('Foo','Bar')
?
Akina solved it:
SELECT * FROM t WHERE JSON_CONTAINS( '["Foo","Bar"]', CONCAT('"', Name, '"') )
From my knowledge you can put multiple WHERE statements on a SQL query
See: https://www.w3schools.com/SQl/sql_where.asp
you just need to add a 'AND' or 'OR' after each condition
SELECT * FROM Customers
WHERE Country='Mexico'
AND Address='Avda. de la Constitución 2222'
OR Address='Mataderos 2312';
;
So you just build the string you need before using
with c# you can do something like (just AND operators):
public List<Data> ExecuteQueryAND(List<string> statements, string table)
{
// initial connection
// ...
string str = $"SELECT * FROM {table}\n";
for (int i =0; i > statements.Count; i++)
{
if( i == 0 )
{
str = str + $"WHERE {statements[i]}\n";
}
str = str + $"\tAND {statements[i]}\n";
}
str = str + ";";
Console.WriteLine("Sql Query: " + str);
// more code to execute sql
}
then when you call it:
// some code ..
FilterList = ExecuteQueryAND( new List<string> { "Access=\"ADMIN\""});
// more code ..
I am creating a Java application that communicates with MySQL database. Using XAMPP 5.6.33-0 and phpMyAdmin. I have the following method that, among other values, inserts a Timestamp into the table RATING:
PreparedStatement pst = myConn.prepareStatement("INSERT INTO RATING
(ratingDate) VALUES(?)");
java.util.Date today = new java.util.Date();
Timestamp ts = new java.sql.Timestamp(today.getTime());
pst.setTimestamp(1, ts);
pst.executeUpdate();
The schema of the RATING relation looks as follows:
CREATE TABLE RATING
(cID INT,
rID INT,
stars INT,
ratingDate TIMESTAMP,
FOREIGN KEY(cID) REFERENCES CUSTOMER(cID) on delete cascade,
FOREIGN KEY(rID) REFERENCES ROOM(rID)
) ;
So attribute ratingDate is defined as Timestamp. Everything works great except when the Timestamp is inserted its value is always set to all zeros: 0000-00-00 00:00:00
I tried converting the Timestamp to string using t.toString and can clearly see that the Timestamp object is created properly. It seems the problem is with setTimestamp() method. Also, converting the data type of ratingDate to just Date and using setDate() method works fine, but setTimestamp() function always sets the attribute value to all zeros.
There are, of course, workaround for this. I could declare the date as varchar, convert Timestamp to a String and insert it using setString() but I am really wondering what the problem may be. Running Eclipse with Tomcat server. No errors in console.
Thank you in advance for any help, I'd be happy to provide any other necessary information.
Avoid legacy date-time classes
The all-zeros values is a mystery. But I can tell you that you are using terrible date-time classes that were supplanted years ago by the java.time classes with the adoption of JSR 310. This is making your work more complicated than it needs to be.
I suggest creating a simple dummy table to narrow down your problem.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime ) ;
Example app
I do not use MySQL. But here is a complete example app using the H2 Database Engine.
package work.basil.example;
import org.h2.jdbcx.JdbcDataSource;
import java.sql.*;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class H2DateTimeExample
{
public static void main ( String[] args )
{
H2DateTimeExample app = new H2DateTimeExample ();
app.demo ();
}
private void demo ( )
{
JdbcDataSource dataSource = new JdbcDataSource ();
dataSource.setURL ( "jdbc:h2:mem:offsetdatetime_example_db;DB_CLOSE_DELAY=-1" ); // Set `DB_CLOSE_DELAY` to `-1` to keep in-memory database in existence after connection closes.
dataSource.setUser ( "scott" );
dataSource.setPassword ( "tiger" );
// Create table.
String sql = "CREATE TABLE person_ ( \n" +
" pkey_ UUID NOT NULL DEFAULT RANDOM_UUID() PRIMARY KEY , \n" +
" name_ VARCHAR NOT NULL , \n" +
"first_contacted_ TIMESTAMP WITH TIME ZONE NOT NULL " +
") ;";
// System.out.println ( sql );
try (
Connection conn = dataSource.getConnection () ;
Statement stmt = conn.createStatement () ;
)
{
stmt.execute ( sql );
} catch ( SQLException e )
{
e.printStackTrace ();
}
// Insert row.
sql = "INSERT INTO person_ ( name_ , first_contacted_ ) \n";
sql += "VALUES ( ? , ? ) \n";
sql += ";";
try (
Connection conn = dataSource.getConnection () ;
PreparedStatement pstmt = conn.prepareStatement ( sql , Statement.RETURN_GENERATED_KEYS ) ;
)
{
OffsetDateTime odt = OffsetDateTime.now ( ZoneOffset.UTC );
pstmt.setString ( 1 , "Jesse Johnson" );
pstmt.setObject ( 2 , odt );
pstmt.executeUpdate ();
ResultSet rs = pstmt.getGeneratedKeys ();
// System.out.println( "INFO - Reporting generated keys." );
// while ( rs.next() ) {
// UUID uuid = rs.getObject( 1 , UUID.class );
// System.out.println( "generated keys: " + uuid );
// }
} catch ( SQLException e )
{
e.printStackTrace ();
}
// Query table.
sql = "TABLE person_ ;";
try (
Connection conn = dataSource.getConnection () ;
PreparedStatement pstmt = conn.prepareStatement ( sql ) ;
)
{
try ( ResultSet rs = pstmt.executeQuery () ; )
{
while ( rs.next () )
{
UUID pkey = rs.getObject ( "pkey_" , UUID.class );
String name = rs.getString ( "name_" );
OffsetDateTime firstContacted = rs.getObject ( "first_contacted_" , OffsetDateTime.class );
System.out.println ( "pkey: " + pkey + " | name: " + name + " | firstContacted: " + firstContacted );
}
}
} catch ( SQLException e )
{
e.printStackTrace ();
}
System.out.println ( "Done." );
}
}
When run.
pkey: b14fd25f-1598-4f09-9475-83ac5967a338 | name: Jesse Johnson | firstContacted: 2019-07-28T02:10:07.731005Z
Done.
After some additional research I figured it out. The problem was that the java Timestamp object uses milliseconds at the end while the timestamp attribute in the MySQL table didn't (it was in the format "yyyy-MM-dd HH:mm:ss"). So this mismatch prevented the insertion of the correct timestamp and instead put a tuple with all zeros into MySQL table. The solution is to format the Timestamp object in the java code to cut off the milliseconds and then insert the Timestamp object into MySQL table:
java.util.Date today = new java.util.Date();
java.sql.Timestamp timestamp = new java.sql.Timestamp(today.getTime());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pst.setObject(4, formatter.format(timestamp));
This worked like a charm. Hope it helps somebody!
I have a jersey java server and a mysql server:
I send a POST with an ArrayList<Long> to the server. Then I want to do a select like ...where long OR long OR long....
Is there an elegant way to solve this problem and not to do always a single select in a for loop?
How can I form a sql-statement with dynamic count of where clauses?
Thank you very mutch.
Instead of OR multiple times, you can use IN with the where clause in the SQL query.
You can read ArrayList object in a loop and set the where clause values.
JAVA code snippet:
int paramCount = list.size();
StringBuilder sqlSelect = new StringBuilder( 1024 );
sqlSelect.append( "select x,y,z from my_table " );
if( paramCount > 0 ) {
sqlSelect.append( "where long_column in ( " );
for( i = 0; i < paramCount; i++ ) {
sqlSelect.append( ( i > 0 ? ", ?" : "?" );
} // for each param
sqlSelect.append( " )" );
} // if list is not empty
// make the prepare statement (pst) with the above sql string
// ...
// now set the parameter values in the query
int paramIndex = 1;
if( paramCount > 0 ) {
for( i = 0; i < paramCount; i++ ) {
pst.setLong( paramIndex++, ( (Long)list.get( i ) ).longValue() );
} // for each param
} // if list is not empty
I try to query in my script my database. The query's parameters depends on what I have defined in my GUI. Sometimes I like to use the NAME in query and sometimes the CITY. Here is the code:
var query = 'STRUCTTYPE: PERSON';
if (value1 != 0) {
query = query + ', NAME: ' + value1;
}
if (value2 != 0) {
query = query + ', CITY: ' + value2;
}
So the string 'query' itself is ok, but when I try to use it in db.query I get error message.
var results = db.query(query);
Any suggestions? Or other ways to handle this problem? Thanks!
The query parameter you pass to ScriptDb.query function must be an object, not a string. Try this:
var query = {STRUCTTYPE: 'PERSON'};
if( value1 != 0 ) //this != 0 seems a weird test, but I'm copying from your example
query.NAME = value1;
if( value2 != 0 )
query.CITY = value2;
var results = db.query(query);