Multiple cypher MATCH queries to get row count - cypher

I am trying to get the row count for each node.
I am using the following cypher:
MATCH (p:Product) WHERE p.modifiedDTS > 10
RETURN {productCount: count(p)};
How can I use this with multiple unrelated matches?
MATCH (p:Product)
MATCH (i:Item)
WHERE p.modifiedDTS > 10
RETURN {productCount: count(p) ,itemCount: count(i)}
This returns 0 as the result, but should return 1 for the productCount.
Found one solution, but there are probably better options out there.
MATCH(p:Product) where p.modifiedDTS > 10
Return count(p) as count, "product" as node
UNION ALL
MATCH(i:Item) where i.modifiedDTS > 10
Return count(i) as count, "item" as node

Use OPTIONAL MATCH that way the where only works on the previous optional match and doesn't throw out other rows.
OPTIONAL MATCH (p:Product)
WHERE p.modifiedDTS > 10
OPTIONAL MATCH (i:Item)
WHERE i.modifiedDTS > 10
RETURN {productCount: count(p) ,itemCount: count(i)}

Related

Filter neo4j result, return distinct combination of node IDs

I have a graph with Airport nodes and Flight relationships, and I want to find triangles from a specific node where the edges are all within 10% length of each other.
MATCH path = (first:Airport{ID: 12953})-[f1:Flight]->
(second:Airport)-[f2:Flight]->
(third:Airport)-[f3:Flight]->
(last:Airport{ID: 12953})
WHERE second.ID <>first.ID AND
third.ID <>first.ID AND
f1.Distance<=(1.1*f2.Distance) AND
f1.Distance<=(1.1*f3.Distance) AND
f2.Distance<=(1.1*f1.Distance) AND
f2.Distance<=(1.1*f3.Distance) AND
f3.Distance<=(1.1*f1.Distance) AND
f3.Distance<=(1.1*f2.Distance)
WITH (first.ID, second.ID, third.ID) as triplet
return count(DISTINCT triplet)
I only want to return a set of nodes once (no matter how many different flights exist between them), but the with line doesn't work. Basically what I want to create is a new type of variable "object" that has the three IDs as its properties and run distinct on that. Is that possible in neo4j? If not, is there some workaround?
You can use the APOC function apoc.coll.sort to sort each list of 3 IDs, so that the DISTINCT option will properly treat lists with the same IDs as being the same.
Here is a simplified query that uses the APOC function:
MATCH path = (first:Airport{ID: 12953})-[f1:Flight]->
(second:Airport)-[f2:Flight]->
(third:Airport)-[f3:Flight]->
(first)
WHERE second <> first <> third AND
f2.Distance<=(1.1*f1.Distance)>=f3.Distance AND
f1.Distance<=(1.1*f2.Distance)>=f3.Distance AND
f1.Distance<=(1.1*f3.Distance)>=f2.Distance
RETURN COUNT(DISTINCT apoc.coll.sort([first.ID, second.ID, third.ID]]))
NOTE: the second <> first test may not be necessary since there should not be any flights (if a "flight" is the same as a "leg") that fly from an airport back to itself.
You can return an object with keys or an array. For example:
UNWIND range(1, 10000) AS i
WITH
{
id1: toInteger(rand()*3),
id2: toInteger(rand()*3),
id3: toInteger(rand()*3)
} AS triplet
RETURN DISTINCT triplet
or
UNWIND range(1, 10000) AS i
WITH
[ toInteger(rand()*3), toInteger(rand()*3), toInteger(rand()*3) ] AS triplet
RETURN DISTINCT triplet
Update. You can simplify your query by reusing a variable in the query, specifying the length of the path and using the list functions:
MATCH ps = (A:Airport {ID: 12953})-[:Flight*3]->(A)
WITH ps
WHERE reduce(
total = 0,
rel1 IN relationships(ps) |
total + reduce(
acc = 0,
rel2 IN relationships(ps) |
acc + CASE WHEN rel1.Distance <= 1.1 * rel2.Distance THEN 0 ELSE 1 END
)) = 0
RETURN count(DISTINCT [n IN nodes(ps) | n.ID][0..3])

Ignore clauses in where based on if you get a result from the select

I want the following sql statement to give me different results based on whether it finds a result within the specific string or it needs to search the whole parent group (so within the table there are for example:
column 1, column 2
a - 1
a - 2
a - 3
b - 5
b - 7
b - 1
so if it can find the result if i put 1 it will display me
a -1
b -1
. the problem is that in the where clause exist both the parent group and the child group
i have tried to use case and also to simulate an if with ands and ors but it didn't work
select 1,
aapv.aapv_keyext1,
aapv.aapv_area,
aapv.aapv_valuecharmax,
aapv.aapv_valuechardefault,
aapv.aapv_valuecharmin, aap.aap_ident
from a_parameter_value aapv,
a_parameter aap
where aap.aap_ident in (string1,string2,string3)
and aap.aap_ref = aapv.aap_ref
and aap.aap_idento = string4
and ((aapv.Aapv_Keyext1 = 'LaD1' --child clause
and aapv.aapv_keyext1 is not null)
or aapv.Aapv_Area = 'LSDe' --parent clause
and aapv.Aapv_Area is null)
I expect the output to be if the aapv_keyext1 value finds any results then the appv_area is not used at all but either only the child clause is used with the above code or both if i remove the is null clause
Okay, you need to provide more information for us to give you a real answer, but I wanted to point out that this section has some logic problems:
and ((aapv.Aapv_Keyext1 = 'LaD1' --child clause
and aapv.aapv_keyext1 is not null)
or aapv.Aapv_Area = 'LSDe' --parent clause
and aapv.Aapv_Area is null)
The first part is saying aapv_keyext1 = 'LaD1' AND aapv_keyext1 is not null; the second half can never be false, so it's redundant. The second part is saying aapv_area = 'LSDe' AND aapv_area is null. This will never be true. So this whole section is equivalent to:
and (aapv.aapv_keyext1 = 'LaD1')
Which probably isn't what you want. You say you want "if the aapv_keyext1 value finds any results then the appv_area is not used at all". I suspect what you mean is that "if any results exist for aapv_keyext1 in any rows then don't use aapv_area" which is more complicated, you need a subquery (or analytic/aggregate functions) to look at what other rows are doing.
select 1,
aapv.aapv_keyext1,
aapv.aapv_area,
aapv.aapv_valuecharmax,
aapv.aapv_valuechardefault,
aapv.aapv_valuecharmin, aap.aap_ident
from a_parameter_value aapv,
a_parameter aap
where aap.aap_ident in (string1,string2,string3)
and aap.aap_ref = aapv.aap_ref
and aap.aap_idento = string4
and (-- prefer keyext1
aapv.Aapv_Keyext1 = 'LaD1'
OR
-- if keyext1 doesn't find results...
(NOT EXISTS (select 1 from a_parameter_value aapv2
where aapv2.aap_ident = aap.aap_ident
and aap2.aap_ref = aap.aap_ref
and aap2.aap_idento = aap.aap_idento
and aapv.Aapv_Keyext1 = 'LaD1')
AND
-- ... use aapv_area
aapv.Aapv_Area = 'LSDe')
);
You can also do this kind of conditional logic with CASE statements, but you're still going to need a subquery or something if you want your logic to depend on the values in rows other than the one currently being looked at.
Let me know if I've misunderstood your question and I'll try to update with a better answer.

LINQ Query based on values in a list?

I'm trying to filter the entity based on the possibility of a list of integers being passed to the query; however it is also possible that no integers as passed into the query. In the example below If a "status" is passed in as a list of integers, i would want to return all results that contain a matching status (integer)
Status As List(Of Integer)
Query as IQueryable(Of db.People) = db.people.asNoTracking.Where(Function(C) c.DeleteFlag = False)
Query = (From q In Query From s In Status Where q.PersonStatus = s)
Assuming if you pass in no statuses, that you want all the records, then:
query=db.people.Where(Function(c) c.DeleteFlag=False)
if (Status.Any())
query=query.Where(Function(c) Status.Contains(c.PersonStatus))
If you want no records when no statuses are passed in then:
if (!Status.Any())
query=new List(Of people).AsQueryable()
else
...
endif

Active record - 3 results found, but only one being returned

The query below is returning that 3 results are available, but it is only returning one entry id.
How can I have the three entry_id's returned?
$this->EE->db->select('entry_id, count(portfolio_number) AS results');
$this->EE->db->from('submissions');
$this->EE->db->where('type_id', '1');
$this->EE->db->where('member_group', $member_group);
$this->EE->db->group_by('portfolio_number');
$this->EE->db->having('results = 3');
$query = $this->EE->db->get();
$submissions = $query->result_array();
print_r($submissions);
EDIT:
I have a table columns entry_id, member_group, type_id and portfolio_number.
The portfolio_number column will have a number between 1 and 7.
I need to query the database for 3 rows that have the same portfolio_number (as well as matching type and member_id) and return the entry_id for each of those three rows.
There must be 3 results, else I don't want to show them.
You can handle it like this
$results = $this->EE->db
->select('entry_id')
->from('submissions')
->where('type_id', '1')
->where('member_group', $member_group)
->group_by('portfolio_number')
->get()
->result_array();
if(count($results)){
return $results
}else {
return false;
}
Your $this->EE->db->group_by('portfolio_number'); is causing a single row with aggregated data to be returned.
If you want all the ids to be returned as well, you can try adding
$this->EE->db->select('GROUP_CONCAT(entry_id) AS entry_ids', false);
and then splitting the entry_ids field in PHP:
str_getcsv($submissions);
Edit: I put in the second argument for the select query to prevent backticks being placed around the custom select query.
Can you please replace this code
$this->EE->db->group_by('portfolio_number'); //It will return only one row per portfolio_number
$this->EE->db->group_by('portfolio_number,entry_id'); // It will return one row per portfolio_number and entry_id
I think it will return 3 rows of different entry_id

Compare two rows in AND condition

just having a problem using the AND operator in SQL as it returns a zero result set.
I have the following table structure:
idcompany, cloudid, cloudkey, idsearchfield, type, userValue
Now I execute the following statement:
SELECT *
FROM filter_view
WHERE
(idsearchfield = 4 and compareResearch(userValue,200) = true)
AND (idsearchfield = 6 and compareResearch(userValue,1) = true)
compareResearch ist just a function that casts the userValue and compares it to the other value and returns true if the value is equal or greater. UserValue is actually stored as a string (that's a decision made 6 years ago)
Okay, I get a zero resultset which is because both criterias in braces () are AND combined and one row can only have one idsearchfield and therefor one of the criterias won't match.
How do I get around this? I NEED the AND Comparison, but it won't work out this way.
I hope my problem is obvious :-)
If you've recognised that both conditions can't ever both be true, in what way can the AND comparison be the correct one?
select *
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
This will return 2 rows (or more). Or are you looking for some way to correlate these two rows so that they appear as a single row?
Okay, so making a tonne of assumptions, because you haven't included enough information in your question.
filter_view returns a number of columns, one of which is some form of record identifier (lets call that ID). It also includes the aforementioned idsearchfield and userValue columns.
What you actually want to find is those id values, for which one row of filter_view has idsearchfield = 4 and compareResearch(userValue,200) = true and another row of filter_view has idsearchfield = 6 and compareResearch(userValue,1) = true
The general term for this is "relational division". In this simple case, and assuming that id/idsearchfield are unique in this view, we can answer it with:
select id,COUNT(*)
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
group by id
having COUNT(*) = 2
If this doesn't answer your question, you're going to have to add more info to your question, including sample data, and expected results.