Groovy - Joining two SQL Select results - mysql

before even explaining anything, I'll just leave you here what I have (a summary tho):
rowsTable1 (it has the result of a SELECT, it contains X rows with Y columns)
rowsTable2 (it has the result of a SELECT, it contains W rows with Z columns)
What I want, is to insert into each rowsTable1 row, a row from rowsTable2, but I need to filter rowsTable2 by an ID I have in rowsTable1.
For example, in rowsTable1, I have an element called superID and another called ultraID, and rowsTable2 has those elements too, and that's what I need to merge both rows.
My question is, how can I filter rowsTable2 to only get the row I want?
rowsTable1.eachWithIndex{ rowT1, i ->
rowT1 << rowT2.firstRow([rowT1.superID],[rowT1.ultraID])
}
Like this?
Thanks!

It looks like you want to use "collect" to create a composite map, as I don't think you'll be allowed to change the list of Rows that came back from the SQL query.
Here's a sample that should do what you want:
// if we start with this data (pretend it's what came back from your queries)
def rowsTable1 = [ [superID :1, ultraID :2, c:'a1b2'], [superID :1, ultraID :3, c:'a1b3'] ]
def rowsTable2 = [ [superID :1, ultraID :3, d:'a1b3extra'], [superID :3, ultraID :4, d:'unfound'], [superID :1, ultraID :2, d:'a1b2extra']]
// Now, join the rows to a List of new "row-like" Maps when superID and ultraID are equal.
def ret = rowsTable1.collect { T1row ->
[:] << T1row << rowsTable2.find { it.superID == T1row.superID && it.ultraID == T1row.ultraID }
}
ret should now be a List of Maps, each of which is the "merged" Row data for all the unique combinations of superID and ultraID in rowsTable1. Note that any data in rowsTable2 that doesn't have a superID/ultraID combo that exists in rowsTable1 is ignored, and that all combos that exist in rowsTable1 should exist in rowsTable2.

Related

mysql select primary record and multiple secondary records as sorted data set

I have two tables: locations and events
Each location can have multiple events. I am successfully doing a single query to grab all the location and matching events, however, the events are being returned as a merged data-set with all of the location data. I need to somehow have each, and all, events, listed as sub-rows so I can properly process them later.
This query:
"select locations.*,events.* FROM locations,events WHERE locations.lid = events.lid AND locations.lid=1001"
Is returning merged data like:
data [array 1]
0: lid: "1001" // location info
name: "Johns Bar"
address1: "123 Main St"
...
...
eventID: "1000" // event info
eName: "Halloween Bash"
eDate: "2018-10-31"
...
...
Is it possible to grab the specific locations.lid and all matching events.lid and have the events records listed as a subset of location data.
Something that would return like:
data [array 1]
0: lid: "1001"
name: "Johns Bar"
address1: "123 Main St"
...
...
Events: [array 5]
0: lid: "1001"
eventID: "1000"
eName: "Halloween Bash"
eDate: "2018-10-31"
...
...
1: lid: "1001"
eventID: "1010"
eName: "Christmas Party"
eDate: "2018-12-17"
...
...
2: [lid: "1001",...]
3: [lid: "1001",...]
4: [lid: "1001",...]
so all matching events will always come back as part of a single returned row? Is there no way to get the secondary records to list as sub-rows/records?
Yes, this is how a JOIN works.
If not, then this will force me to do two queries...or is there another method?
No, you don't have to run multiple queries.
You can fetch your result set as SQL returns it, with pairings of matching location and event rows. Make sure you sort by location in your SQL query.
Then as you fetch the rows of result, keep track of the "current" location in a variable in your client app. If you fetch a row and its location is the same as the location you had seen before, then ignore it.
Pseudocode:
sql = SELECT ... FROM location JOIN event ... ORDER BY location
execute sql
location = nil
while row = fetch():
if row[location] != location:
print location
end if
location = row[location] # for next time
print event
end while
This is a common pattern for processing SQL result sets.

Importing CSV While Creating Relationship In Neo4j

I am trying to create a relationship between two different graphs, using information in a CSV file. I built the query the way I did because the size of each graph, one being 500k+ and the other 1.5m+.
This is the query I have:
LOAD CSV WITH HEADERS FROM "file:///customers_table.csv" AS row WITH row
MATCH (m:Main) WITH m
MATCH (c:Customers) USING INDEX c:Customers(customer)
WHERE m.ASIN = row.asin AND c.customer = row.customer
CREATE (c)-[:RATED]->(m)
This is the error I receive:
Variable `row` not defined (line 4, column 16 (offset: 164))
"WHERE m.ASIN = row.asin AND c.customer = row.customer"
^
An example of the Main table is:
{
"ASIN": "0827229534",
"totalreviews": "2",
"categories": "2",
"title": "Patterns of Preaching: A Sermon Sampler",
"avgrating": "5",
"group": "Book"
}
And an example of a customer is:
{
"customer": "A2FMUVHRO76A32"
}
And inside the customers table csv, I have:
Customer, ASIN, rating
A2FMUVHRO76A32, 0827229534, 5
I can't seem to figure out why it's throwing back that error.
The first WITH clause in your query (WITH row) is unnecessary, but you have to add the variable to the WITH clause. So this version compiles.
LOAD CSV WITH HEADERS FROM "file:///customers_table.csv" AS row
MATCH (m:Main)
WITH m, row
MATCH (c:Customers) USING INDEX c:Customers(customer)
WHERE m.ASIN = row.asin AND c.customer = row.customer
CREATE (c)-[:RATED]->(m)
The reason for this is, that, in essence, WITH chains two query parts together, while limiting the scope to its variables (and in some cases, also performing calculations, aggregations, etc.).
Having said that, you do not even need the second WITH clause, you can just omit it and even merge the two MATCH clauses to a single one:
LOAD CSV WITH HEADERS FROM "file:///customers_table.csv" AS row
MATCH (m:Main), (c:Customers) USING INDEX c:Customers(customer)
WHERE m.ASIN = row.asin AND c.customer = row.customer
CREATE (c)-[:RATED]->(m)

How to use ransack to search MySQL JSON array in Rails 5

Rails 5 now support native JSON data type in MySQL, so if I have a column data that contains an array: ["a", "b", "c"], and I want to search if this column contains values, so basically I would like to have something like: data_json_cont: ["b"]. So can this query be built using ransack ?
Well I found quite some way to do this with Arrays(not sure about json contains for hash in mysq). First include this code in your active record model:
self.columns.select{|column| column.type == :json}.each do |column|
ransacker "#{column.name}_json_contains".to_sym,
args: [:parent, :ransacker_args] do |parent, args|
query_parts = args.map do |val|
"JSON_CONTAINS(#{column.name}, '#{val.to_json}')"
end
query = query_parts.join(" * ")
Arel.sql(query)
end
end
Then assuming you have class Shirt with column size, then you can do the following:
search = Shirt.ransack(
c: [{
a: {
'0' => {
name: 'size_json_contains',
ransacker_args: ["L", "XL"]
}
},
p: 'eq',
v: [1]
}]
)
search.result
It works as follows: It checks that the array stored in the json column contains all elements of the asked array, by getting the result of each json contains alone, then multiplying them all, and comparing them to arel predicate eq with 1 :) You can do the same with OR, by using bitwise OR instead of multiplication.

Append value to JSON decode array parameter stored in MySQL

Im trying to work out how to append a zero to a specific JSON decoded array value for multiple records stored in a MySQL table according to some conditions.
for example, for table 'menu', column 'params'(text) have records containing JSON decoded arrays of this format:
{"categories":["190"],"singleCatOrdering":"","menu-anchor_title":""}
and column 'id' has a numeric value of 90.
my goal is to add a zero to 'categories' value in menu.params whenever (for example) menu.id is under 100.
for this records the result being
{"categories":["1900"],"singleCatOrdering":"","menu-anchor_title":""}
so im looking for a SQL Query that will search and find the occurrences of "categories": ["999"] in the Database and update the record by adding a zero to the end of the value.
this answer is partially helpful by offering to use mysql-udf-regexp but its referring to REPLACE a value and not UPDATE it.
perhaps the REGEXP_REPLACE? function will do the trick. i have never used this library and am not familiar with it, perhaps there is an easier way to achieve what i need ?
Thanks
If I understand your question correctly, you want code that does something like this:
var data = {
"menu": {
"id": 90,
"params": {
"categories": ["190"],
"singleCatOrdering": "",
"menu-anchor_title": ""
}
}
};
var keys = Object.keys(data);
var columns;
for (var ii = 0, key; key = keys[ii]; ii++) {
value = data[key];
if (value.id < 100) {
value.params.categories[0] += "0";
alert(value.params.categories[0]);
}
}
jsFiddle
However, I am not using a regular expression at all. Perhaps if you reword the question, the necessity of a regex will become clearer.

ArangoDB custom sort order

I would like to sort by a field in a specific order, lets say 2,4,1,5,3.
In MySQL I could use ORDER BY FIELD(id,2,4,1,5,3).
Is there anything equivalent for ArangoDB?
I think it should be possible to use the POSITION AQL function, which can return the position of an element inside an array
FOR i IN [ 1, 2, 3, 4, 5 ] /* what to iterate over */
SORT POSITION([ 2, 4, 1, 5, 3 ], i, true) /* order to be returned */
RETURN i
This will return:
[ 2, 4, 1, 5, 3 ]
Update: my original answer included the CONTAINS AQL function, however, it should be POSITION!
Unfortunately, there is no direct equivalent for that, at the moment.
However, there are ways to accomplish that by yourself.
1) By constructing an AQL query:
The query would run through your sort value array and query the DB for every defined value. Each of those results would then be added to the final output array.
Mind you, that this does have a performance penalty, because there is one query for every value. If you are defining only a few ones, I guess it will be tolerable, but if you have to define for example tens or hundreds, it will lead to n+1 queries (where n is the number of custom sorted values).
The "+1" is the last query, which should get the result of all the other values, which are not defined in your custom sort array and also append these to your output array.
That would look like the following snippet, which you can copy into your AQL Editor and run it.
Notes for the snippet:
I am first creating an array, which would represent the collection we
would query.
Then I am setting the defined sort values.
After that, the actual AQL statement does its job.
Also, note the FLATTEN function at the outer RETURN statement, which is required, because in the first loop we are getting result arrays for each defined sort value. These have all to be flatten down to the same level in order to be processed as a unique result set (instead of many encapsulated small ones).
/* Define a dummy collection-array to work with */
LET a = [
{
"_id": "a/384072353674",
"_key": "384072353674",
"_rev": "384073795466",
"sort": 2
},
{
"_id": "a/384075040650",
"_key": "384075040650",
"_rev": "384075827082",
"sort": 3
},
{
"_id": "a/384077137802",
"_key": "384077137802",
"_rev": "384078579594",
"sort": 4
},
{
"_id": "a/384067504010",
"_key": "384067504010",
"_rev": "384069732234",
"sort": 1
},
{
"_id": "a/384079497098",
"_key": "384079497098",
"_rev": "384081004426",
"sort": 5
}
]
/* Define the custom sort values */
LET cSort = [5,3,1]
/* Gather the results of each defined sort value query into definedSortResults */
LET definedSortResults = (
FOR u in cSort
LET d = (
FOR docs IN `a`
FILTER docs.`sort` == u
RETURN docs
)
RETURN d
)
/* Append the the result of the last (all the non-defined sort values) query to the results of the definedSortResults into the output array */
LET output = (
APPEND (definedSortResults, (
FOR docs IN `a`
FILTER docs.`sort` NOT IN cSort
RETURN docs
)
)
)
/* Finally FLATTEN and RETURN the output variable */
RETURN FLATTEN(output)
2) A different approach would be, to extend AQL with a function written in JavaScript, that would essentially do the same steps as above.
Of course, you could also open up a feature request on ArangoDB's GitHub Page, and maybe the nice folks at ArangoDB will consider it for inclusion. :)
Hope that helps