I need to store multiple circles in a single geometry column in PostGIS.
So far I can store only one like this:
UPDATE element SET geo = ST_Buffer(ST_MakePoint(-71.1043443253471, 42.3150676015829), 6, 'quad_segs=8') WHERE id = 1;
Is there a way to use GEOMETRYCOLLECTION here?
Thanks in advance.
Aggregate your buffers using ST_Union and then create the collection with ST_ForceCollection, e.g. to append a buffer to an existing geometry:
UPDATE element
SET geo =
ST_ForceCollection(
ST_Union(geo, ST_Buffer(ST_MakePoint(-80.10, 45.31), 3) ))
WHERE id = 1;
Demo: db<>fiddle
SELECT
ST_ForceCollection(
ST_Union(
ST_Buffer(ST_MakePoint(-71.10, 42.31), 6),
ST_Buffer(ST_MakePoint(-80.10, 45.31), 3)
));
st_astext
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GEOMETRYCOLLECTION(POLYGON((-77.1576441587903 44.72472903395162,-77.32836140246613 44.161949702904735,-77.60559116309236 43.6432893009412,-77.97867965644035 43.188679656440364,-78.43328930094118 42.81559116309237,-78.95194970290473 42.538361402466144,-79.51472903395161 42.36764415879031,-80.1 42.31,-80.68527096604838 42.36764415879031,-81.24805029709526 42.53836140246614,-81.76671069905879 42.815591163092364,-82.22132034355963 43.18867965644036,-82.59440883690763 43.64328930094119,-82.87163859753385 44.16194970290473,-83.04235584120968 44.72472903395161,-83.1 45.309999999999995,-83.04235584120968 45.89527096604838,-82.87163859753386 46.45805029709526,-82.59440883690763 46.9767106990588,-82.22132034355964 47.431320343559634,-81.7667106990588 47.80440883690763,-81.24805029709528 48.08163859753386,-80.68527096604839 48.25235584120969,-80.10000000000001 48.31,-79.51472903395162 48.2523558412097,-78.95194970290474 48.08163859753387,-78.4332893009412 47.80440883690765,-77.97867965644036 47.431320343559655,-77.60559116309237 46.97671069905883,-77.32836140246614 46.45805029709529,-77.1576441587903 45.89527096604841,-77.1 45.31,-77.1576441587903 44.72472903395162)),POLYGON((-65.21528831758062 41.139458067903234,-65.55672280493228 40.01389940580947,-66.11118232618472 38.976578601882395,-66.8573593128807 38.06735931288072,-67.76657860188237 37.32118232618473,-68.80389940580945 36.766722804932286,-69.92945806790321 36.42528831758062,-71.09999999999998 36.31,-72.27054193209675 36.425288317580616,-73.39610059419053 36.76672280493228,-74.4334213981176 37.321182326184726,-75.34264068711927 38.06735931288071,-76.08881767381526 38.97657860188238,-76.64327719506771 40.01389940580945,-76.98471168241937 41.13945806790321,-77.1 42.30999999999998,-76.98471168241937 43.48054193209675,-76.64327719506772 44.60610059419052,-76.08881767381529 45.643421398117596,-75.3426406871193 46.55264068711927,-74.43342139811763 47.29881767381526,-73.39610059419056 47.85327719506771,-72.27054193209679 48.19471168241938,-71.10000000000002 48.31,-69.92945806790325 48.19471168241939,-68.80389940580949 47.85327719506773,-67.76657860188242 47.29881767381529,-66.85735931288073 46.55264068711931,-66.11118232618475 45.643421398117646,-65.55672280493229 44.60610059419057,-65.21528831758062 43.48054193209681,-65.1 42.31,-65.21528831758062 41.139458067903234)))
(1 row)
Or using a CTE
WITH j (geom) AS (
VALUES (ST_Buffer(ST_MakePoint(-71.10, 42.31), 6)),
(ST_Buffer(ST_MakePoint(-80.10, 45.31), 3))
)
SELECT ST_ForceCollection(ST_Union(geom)) FROM j;
st_astext
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GEOMETRYCOLLECTION(POLYGON((-77.1576441587903 44.72472903395162,-77.32836140246613 44.161949702904735,-77.60559116309236 43.6432893009412,-77.97867965644035 43.188679656440364,-78.43328930094118 42.81559116309237,-78.95194970290473 42.538361402466144,-79.51472903395161 42.36764415879031,-80.1 42.31,-80.68527096604838 42.36764415879031,-81.24805029709526 42.53836140246614,-81.76671069905879 42.815591163092364,-82.22132034355963 43.18867965644036,-82.59440883690763 43.64328930094119,-82.87163859753385 44.16194970290473,-83.04235584120968 44.72472903395161,-83.1 45.309999999999995,-83.04235584120968 45.89527096604838,-82.87163859753386 46.45805029709526,-82.59440883690763 46.9767106990588,-82.22132034355964 47.431320343559634,-81.7667106990588 47.80440883690763,-81.24805029709528 48.08163859753386,-80.68527096604839 48.25235584120969,-80.10000000000001 48.31,-79.51472903395162 48.2523558412097,-78.95194970290474 48.08163859753387,-78.4332893009412 47.80440883690765,-77.97867965644036 47.431320343559655,-77.60559116309237 46.97671069905883,-77.32836140246614 46.45805029709529,-77.1576441587903 45.89527096604841,-77.1 45.31,-77.1576441587903 44.72472903395162)),POLYGON((-65.21528831758062 41.139458067903234,-65.55672280493228 40.01389940580947,-66.11118232618472 38.976578601882395,-66.8573593128807 38.06735931288072,-67.76657860188237 37.32118232618473,-68.80389940580945 36.766722804932286,-69.92945806790321 36.42528831758062,-71.09999999999998 36.31,-72.27054193209675 36.425288317580616,-73.39610059419053 36.76672280493228,-74.4334213981176 37.321182326184726,-75.34264068711927 38.06735931288071,-76.08881767381526 38.97657860188238,-76.64327719506771 40.01389940580945,-76.98471168241937 41.13945806790321,-77.1 42.30999999999998,-76.98471168241937 43.48054193209675,-76.64327719506772 44.60610059419052,-76.08881767381529 45.643421398117596,-75.3426406871193 46.55264068711927,-74.43342139811763 47.29881767381526,-73.39610059419056 47.85327719506771,-72.27054193209679 48.19471168241938,-71.10000000000002 48.31,-69.92945806790325 48.19471168241939,-68.80389940580949 47.85327719506773,-67.76657860188242 47.29881767381529,-66.85735931288073 46.55264068711931,-66.11118232618475 45.643421398117646,-65.55672280493229 44.60610059419057,-65.21528831758062 43.48054193209681,-65.1 42.31,-65.21528831758062 41.139458067903234)))
(1 row)
LARAVEL 5.4 (but probably it's a more general SQL question)
Hello! I have a table with a structure:
Suppose it's my model 'Table'.
I want a query which:
uses (receives) variables :
$id of array ['id', 'string', integer]
where string is '<' or '>'
$status_not_bad = bool;
(if true - include all rows where 'status' !== 'bad' AND 'status' IS NULL);
for example, we are given:
$id = ['id', '>', 0];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id > 0" returns rows 1 and 3.
but if we given:
$id = ['id', '<', 3];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id < 3" returns row 1
(it should be same query which return those results using those variables).
I've never used laravel before so my syntax could be off, but I know you want to use MySQL's ifNull function for this:
Table::where([['id', '>', 0], ['number', '>', 2])->whereRaw("IfNull(status, 'blah') <> 'bad'")->get();
Just chain your ->where() clauses. Maybe also consider wrapping them to prevent conflicting with any additional:
$results = Table::where("id", ">" 0)
->orWhere("number", ">", 2)
->orWhereNull("status")
->get();
Or, wrapped:
$results = Table::where(function($query){
$query->where("id", ">" 0)
->orWhere("number", ">", 2)
->orWhereNull("status");
})->get();
If you want to see what the actual query you're executing is, replace ->get() with ->toSql(), and use dd($result);:
$results = Table::where(...)->toSql();
dd($results);
Edit: Sounds like we need multiple wrapping queries, due to multiple conditions:
$results = Table::where(function($query){
$query->where("status", "!=", "bad")
->where("id", "<", 3); -- "status is not bad and id < 3"
})->orWhere(function($query){
$query->where("status", "!=", "bad")
->where("id", ">", 0); -- "status is not bad and id > 0"
})->get();
That should handle paired conditions as noted in your comment.
I want to build (for example) the following sql query where the position field of the matched data rows should be incremented by one:
UPDATE images SET position = position + 1 WHERE (position > 2 AND position <= 4)
I've tried to build the query with CakePHP 3's query builder:
$query->update()
->set(['position' => 'position + 1'])
->where(['position >' => 2])
->andWhere(['position <=' => 4])
->execute();
Due to the fact that position is an integer, CakePHP converts the expression 'position + 1' to 0 and don't pass 'position + 1' to the sql query.
Is there a way to build this query with the CakePHP query builder or must I use a raw sql statement for this?
the correct way to do it should be
$expression = new QueryExpression('position = position + 1');
$query->update()
->set([$expression])
->where(['position >' => 2])
->andWhere(['position <=' => 4])
->execute();
but I guess you could simply do
set(['position = position + 1']);
see the manual
function get_patient_balance($pid) {
if ($GLOBALS['oer_config']['ws_accounting']['enabled'] === 2) {
$brow = sqlQuery("SELECT SUM(fee) AS amount FROM billing WHERE " .
"pid = ? AND billed = 1 AND activity = 1", array($pid) );
$srow = sqlQuery("SELECT SUM(fee) AS amount FROM drug_sales WHERE " .
"pid = ?", array($pid) );
$drow = sqlQuery("SELECT SUM(pay_amount) AS payments, " .
"SUM(adj_amount) AS adjustments FROM ar_activity WHERE " .
"pid = ?", array($pid) );
return sprintf('%01.2f', $brow['amount'] + $srow['amount']
- $drow['payments'] - $drow['adjustments']);
}
Above is the function that I am working with. In this function $brow creates an array from the billing table. In this array there are negative numbers. I want to be able to exclude these numbers from the the SUM(fee) AS amount so that I am adding up the positive number totals only.
I want to be able to exclude these numbers from the the SUM(fee) AS amount so that I am adding up the positive number totals only.
So, you just want to add all fee > 0, right? I think this would do the trick if I got you right:
$brow = sqlQuery("SELECT SUM(fee) AS amount FROM billing WHERE " .
"pid = ? AND billed = 1 AND activity = 1 and fee > 0", array($pid) );
I'd like to see if a migration of a dataset from PostgreSQL to Redis has a positive influence on a particular search query. Unfortunately, I don't really know how to organize the keys and values.
What I want is a that users are able to supply a list of properties and the application delivers a list of items in an ascending order of properties that have not been entered.
For example:
Item #1 { prop1, prop2, prop4, prop7 } Query: "prop1 prop3 prop4 prop5"
Item #2 { prop7, prop8 } Result: Item #3
Item #3 { prop2, prop3, prop5 } Item #1
Item #2
What I have come up with so far:
#!/usr/bin/python
properties = (1, 3, 4, 5)
items = ["Properties:%s:items" % id for property in properties ]
redis.zunionstore("query:related_items", items)
redis.zinterstore("query:result", { "Items:all": 1, "query:related_items": -1 })
This builds a sorted set of Items (all with a score of 1) that are connected with the user-entered Propertys. Afterwards, an intersection with the sorted set of all Items (where each value's score is the number of Propertys) is calculated. The weights are set to create a score of 0 if all Propertys of an Item are supplied in the query.
As the number of Items is about 600.000 entries this query takes approximately 4-6 seconds. Is there a better way to accomplish this?
I imagine you're looking for a Python solution, but the Ohm library for Ruby is my favorite of the Redis-based database analogues. Considering the similarities between Python and Ruby and Ohm's exceptional documentation, you might find some inspiration.
EDIT: Used real properties as stated in comments.
I think I did it (once more). I used PHPRedis.
I used sorted sets too, but I inverted your schema: Each zset represents an ingredient, and each recipe id is a member of that zset. So every zset has the same number of members, i.e., every recipe on the application. Every recipe uses or not a ingredient. That defines the score.
Loading is somewhat expensive, but query is done under 3s, for a sample with 12 ingredients and 600.000 recipes. (you've got a lot of them for sure!).
Loading
Pseudo-code:
For every ingredient i on the system
For every recipe j on the system
If recipe j uses the ingredient i Then
score = 1
INCR recipe:j:ing_count //Will help sorting
RPUSH recipe:j:ing_list i //For listing all ingredients in recipe
Else
score = 0
End If
ZADD ing:i score j
End For
End For
Code:
#!/usr/bin/php
<?
### Total of ingredients
define('NUM_OF_ING',12);
### Total of recipes
define('NUM_OF_RECIPES',600000);
$redis = new \Redis();
$redis->connect('localhost');
for ($ing=1; $ing<=NUM_OF_ING; $ing++) {
for ($recipe=1; $recipe<=NUM_OF_RECIPES; $recipe++) {
$score = rand() % 2;
if ($score == 1) {
$redis->incr("recipe:$recipe:ing_count");
$redis->rpush("recipe:$recipe:ing_list", $ing);
}
$redis->zAdd("ing:$ing", $score, $recipe);
}
}
echo "Done.\n";
?>
Querying
Before I paste the PHP code and measured running time, let me do some observations:
Sorting is done based on the number of ingredients used (sum of the zsets in query). If two recipes use all ingredients that are in query, then the tie-break is done by the number of additional ingredients that one recipe has. More ingredients, higher position.
The sum is handled by ZINTERSTORE. The zset with sums is stored in result.
Then a SORT command looks in the count key for each recipe, tailoring the order with this additional constraint.
Code:
#!/usr/bin/php
<?
$redis = new \Redis();
$redis->connect('localhost');
//properties in query
$query = array('ing:2', 'ing:4', 'ing:5');
$weights = array(1, 1, 1);
//intersection
$redis->zInter('result', $query, $weights, 'sum');
//sorting
echo "Result:\n";
var_dump($redis->sort('result', array('by'=>'recipe:*:ing_count', 'sort'=>'desc', 'limit'=>array(0,10))));
echo "End.\n";
?>
Output and running time:
niloct#Impulse-Ubuntu:~$ time ./final2.php
Result:
array(10) {
[0]=>
string(4) "5230"
[1]=>
string(5) "79549"
[2]=>
string(4) "2871"
[3]=>
string(3) "336"
[4]=>
string(6) "109279"
[5]=>
string(4) "5352"
[6]=>
string(5) "16868"
[7]=>
string(3) "690"
[8]=>
string(4) "3174"
[9]=>
string(4) "8795"
}
End.
real 0m2.930s
user 0m0.016s
sys 0m0.004s
niloct#Impulse-Ubuntu:~$ redis-cli lrange recipe:5230:ing_list 0 -1
1) "12"
2) "11"
3) "10"
4) "9"
5) "8"
6) "7"
7) "6"
8) "5"
9) "4"
10) "3"
11) "2"
12) "1"
Hope that helps.
PS: Can you post your performance measures after trying this ?