SQL Server get a JSON of all distinct columns grouped by a different column - sql

I have a table that looks like this:
What I want to do is convert it to a JSON that has all distinct years as keys, and an array of Make as value for each key. So based on the image, it would be something like this:
{ "1906": ["Reo", "Studebaker"], "1907": ["Auburn", "Cadillac", "Duryea", "Ford"], ... }
Could someone please help me on how to write a query to achieve this? I've never worked with converting SQL -> JSON before, and all I know is to use FOR JSON to convert a query to JSON.

I managed to solve this for whoever needs something similar. However, I think this way is inefficient and I would love for someone to tell me a better method.
I first ran this SQL query:
WITH CTE_Make AS
(
SELECT [Year], [Make]
FROM VehicleInformation
GROUP BY [Year], [Make]
)
SELECT
( SELECT
[Year] AS Year,
STRING_AGG([Make],',') AS MakeList
FOR JSON PATH,
WITHOUT_ARRAY_WRAPPER)
FROM CTE_Make
GROUP BY [Year]
This gave me the JSON in a different format from what I wanted. I stored this in a file "VehicleInformationInit.json", and loaded it in JS as variable vehicleInfoInitJsonFile and ran the following code in JavaScript:
var dict = {};
$.getJSON(vehicleInfoInitJsonFile, function
(result) {
result.forEach(x => {
var makeList = x.MakeList.split(',');
dict[x.Year] = makeList;
})
var newJSON = JSON.stringify(dict);
});
I simply copied the contents of newJSON by attaching a debugger into my required file. However, you can easily use fs and store it in a file if you want to.

Related

How to retrive information from a json substring in a json column in sql query

I have a table that looks like this:
[type] [localid] [data] [executed by]
in the data column there is json
{
"type":"music",
"local_id":"00000086",
"recording":{
"album":null,
"title":"null",
"local_id":"OUHA_A46013SG0001",
"composers":[
"null"
],
"label_name":"null",
"main_artist":"null",
"production_country":null
},
"starts_at":null,
"parallel_hash":"8fe1dfd71f8c19be83806455d5194532",
"report_id":"6bd9e074-5f38-402f-a706-7916def5a9e1",
"duration_in_seconds":120.4
}
i am able to retrive all information into a column for every information except i cannot seperate the information in the recording {}.
I have used select data::json->>'type' as type, and so on... and have got the info
[type][localid][recording][starts_at][report_id][duration_in_seconds]
but i also want the information seperated in the recording data. so that the result is
[type][local_id][recording_album][recording_title][recording_local_id][recording_composers][recording_label_name][recording_main_artist][recording_production_country][starts_at][parallel_hash][report_id][duration_in_seconds]
Can anyone show me how?
Found it out using this....
data::json->'recording'->>'album' as album,
data::json->'recording'->>'title' as title,
and so on

SQL Server extract first array element from JSON

I have json stored in one of the columns in SQL Server and I need to modify it to remove the square brackets from it. The format is as below. Can't seem to find a good way of doing it.
[ { "Message":"Info: this is some message here.", "Active":true } ]
One way is to do it using below query, but this query is very very slow and I need to run on a very large set of data.
select a.value
from dbo.testjson e
cross apply OPENJSON(e.jsontext) as a
where isjson(e.jsontext) = 1
The only other way I can think of is just doing string manipulation but it can be error prone. Could someone help with this?
Ok, figured it out:
select
json_query(
'[{"Message":"Info: this is some message here.","Active":true}]',
'$[0]'
)
This will return the inner message.
You should add the property name, in this case Message, in order to get only that part. Keep in mind that it's case sensitive. Something like;
select json_value('[{"Message":"Info: this is some message here.","Active":true}]', '$[0].Message')

Merging column returned by inner join in sql

I have two table interest and subint, I want to get data related to every interest so I have tried inner join select interest,subinterest from interest inner join subint on subint.interest_id = interest.id; and the result is
"interest" "subinterest"
"foodie" "tea"
"foodie" "biryani"
"foodie" "chocolate"
"foodie" "cookies"
"foodie" "fast-food"
"cooking" "cooking"
Is there any way to format my output and make it like
"interest" "subinterest"
"foodie" "tea"
"biryani"
"chocolate"
"cookies"
"fast-food"
"cooking" "cooking"
is it possible through any SQL query? or I need to do it by coding.
I want this because I am creating an API using node and knex.js and I want the JSON to be well formatted
{
"interest": "foodie",
"subinterest": "coffee",
"subinterest": "tea",
"subinterest": "biryani"
}
Construct the JSON you want in Postgres. This gives you a JSON record per row, which is what I think you want:
select row_to_json(i)
from (select interest, array_agg(subinterest) as subinterests
from t
group by interest
) i;
Here is a db<>fiddle.
You should try and build an object or array structure like this:
arr=[{interest:"foodie",
subinterest:["tea","biryani","chocolate",
"cookies","fast-food"]},
{interest:"cooking",
subinterest:["cooking"]}];
outside SQL by using some serverside code like PHP, then transport it via a JSON string for "safe consumption" by your knex.js script.
(The above code depicts the resulting Javascript array, after JSON parsing.)

U-sql call data in json array

I have browsed the web and forum to download the data from the file json, but my script does not work.
I have a problem with downloading the list of objects of rates. Can someone please help? I can not find fault.
{"table":"C","no":"195/C/NBP/2016","tradingDate":"2016-10-06","effectiveDate":"2016-10-07","rates":
[
{"currency":"dolar amerykański","code":"USD","bid":3.8011,"ask":3.8779},
{"currency":"dolar australijski","code":"AUD","bid":2.8768,"ask":2.935},
{"currency":"dolar kanadyjski","code":"CAD","bid":2.8759,"ask":2.9339},
{"currency":"euro","code":"EUR","bid":4.2493,"ask":4.3351},
{"currency":"forint (Węgry)","code":"HUF","bid":0.013927,"ask":0.014209},
{"currency":"frank szwajcarski","code":"CHF","bid":3.8822,"ask":3.9606},
{"currency":"funt szterling","code":"GBP","bid":4.8053,"ask":4.9023},
{"currency":"jen (Japonia)","code":"JPY","bid":0.036558,"ask":0.037296},
{"currency":"korona czeska","code":"CZK","bid":0.1573,"ask":0.1605},
{"currency":"korona duńska","code":"DKK","bid":0.571,"ask":0.5826},
{"currency":"korona norweska","code":"NOK","bid":0.473,"ask":0.4826},
{"currency":"korona szwedzka","code":"SEK","bid":0.4408,"ask":0.4498},
{"currency":"SDR (MFW)","code":"XDR","bid":5.3142,"ask":5.4216}
],
"EventProcessedUtcTime":"2016-10-09T10:48:41.6338718Z","PartitionId":1,"EventEnqueuedUtcTime":"2016-10-09T10:48:42.6170000Z"}
This is my script in sql.
#trial =
EXTRACT jsonString string
FROM #"adl://kamilsepin.azuredatalakestore.net/ExchangeRates/2016/10/09/10_0_c60d8b8895b047c896ce67d19df3cdb2.json"
USING Extractors.Text(delimiter:'\b', quoting:false);
#json =
SELECT Microsoft.Analytics.Samples.Formats.Json.JsonFunctions.JsonTuple(jsonString) AS rec
FROM #trial;
#columnized =
SELECT
rec["table"]AS table,
rec["no"]AS no,
rec["tradingDate"]AS tradingDate,
rec["effectiveDate"]AS effectiveDate,
rec["rates"]AS rates
FROM #json;
#rateslist =
SELECT
table, no, tradingDate, effectiveDate,
Microsoft.Analytics.Samples.Formats.Json.JsonFunctions.JsonTuple(rates) AS recl
FROM #columnized;
#selectrates =
SELECT
recl["currency"]AS currency,
recl["code"]AS code,
recl["bid"]AS bid,
recl["ask"]AS ask
FROM #rateslist;
OUTPUT #selectrates
TO "adl://kamilsepin.azuredatalakestore.net/datastreamanalitics/ExchangeRates.tsv"
USING Outputters.Tsv();
You need to look at the structure of your JSON and identify, what constitutes your first path inside your JSON that you want to map to correlated rows. In your case, you are really only interested in the array in rates where you want one row per array item.
Thus, you use the JSONExtractor with a JSONPath that gives you one row per array element (e.g., rates[*]) and then project each of its fields.
Here is the code (with slightly changed paths):
REFERENCE ASSEMBLY JSONBlog.[Newtonsoft.Json];
REFERENCE ASSEMBLY JSONBlog.[Microsoft.Analytics.Samples.Formats];
#selectrates =
EXTRACT currency string, code string, bid decimal, ask decimal
FROM #"/Temp/rates.json"
USING new Microsoft.Analytics.Samples.Formats.Json.JsonExtractor("rates[*]");
OUTPUT #selectrates
TO "/Temp/ExchangeRates.tsv"
USING Outputters.Tsv();

Linq.Where-to-SQL on a text field comparing to a list of values

Customer.text is a field in an T-SQL DB (that I do not control and thus may not alter) of type "text".
I'd like to do something like this:
List<string> compare = new List<string>();
compare.Add("one");
compare.Add("two");
var q = from t in customer
where t.text.Contains( compare.First())
select t;
this will work.
But now I'd like to do something like: (!NOT WORKING!)
var q = from t in customer
where compare.Contains( t.text )
select t;
How can I achieve this? Is it even possible?
EDIT: The problem is obviously not exactly clear: A text column in SQL cannot be queried using "=" but only with LIKE. Thus the compare.Contains( t.text ) will result in an error, as it is converted into a query using "=".
What I did not tell - I thought it is irrelevant - is, that I use LINQ-to-ORM (LLBLGen in this case).
What I tried instead:
var q = from t in customer
where compare.Any( x => t.text.Contains(x) )
select t;
Now this did not work also. Currently I'm not at work, but the exception was something with a ConstantExpression not being convertable into a SetExpression.
I hope this gave some clarification.
EDIT2:
Joseph pointed this out to me: PredicateBuilder. It creates an Expression on a given ObjectType.
Now my problem is, that my type is an anonymous type out of multiple joins.
Is there an easy or elegant way to handle this?
Now I might be missing something, but your code looks like it should work. Did you include the namespaces at the top of the file?
using System.Linq;
using System.Linq.Expressions;
You could also rewrite it without the Linq2Sql syntax, like:
var q = customer.Where(c => compare.Contains(c.text));
You could build your query using LinqKit's free predicate builder class. Here is a blog post which describes its use and has a link to the download site.
http://thecodeslinger.wordpress.com/2008/10/28/linqkit-predicatebuildert-goodness/
Below is a code sample from the post
//First get a list of keywords that match the description entered.
string[] parts = txtInclude.Text.Split(new[] {‘ ‘});
string[] noparts = null;
if(txtButNot.Text.Trim().Length > 0)
noparts = txtExclude.Text.Trim().Split(new[] {‘ ‘});
var pred = PredicateBuilder.True<Pet>();
//here is where you would loop through your compare object
parts.ForEach(p => pred = pred.And(pl => pl.description.Contains(p)));
if(noparts != null)
noparts.ForEach(p => pred = pred.And(pl => !pl.description.Contains(p)));
var pets = from s in db.Pets.Where(pred)
select s;
You have to convert the text field to string
var query = from t in dataContext.table
where compare.Contains(t.textField.ToString())
select t;