neo4j delete a node in linked list - database

I have a list of posts that belong to a user. The posts are structured as linked list that belongs to a given user.
I am having deleting the a given node while preserving the data structure.
Here is an illustration of the structure.
In my list attempt I have written the query below, however it does not work since the MATCH does not return anything in the sub-queries.
I thought about using OPTIONAL MATCH in the sub-queries, however that results in exceptions.
MATCH(node:Post)
WHERE ID(node) = 2749
WITH node
MATCH(user:User)-[:OWNS]->(node)-[:PREV]->(nextNode:Post)
CREATE(user)-[:OWNS]->(nextNode)
WITH node
MATCH(prevNode:Post)-[:PREV]->(node)-[:PREV]->(nextNode:Post)
CREATE(prevNode)-[:PREV]->(nextNode)
WITH node
DETACH DELETE node
I assumed that if a pattern in a sub-query fails than the rest of the sub-query will be skipped and the next sub-query will still execute. But it seems that the whole thing does not get executed.
How do we perform something like in the following in sub-queries without halting the execution.
IF pattern matches
THEN
CREATE EDGE
IF pattern matches
THEN
Do something else
Solution
stdob--'s answer is the closest to the right solution, however it fails to delete nodes at the end of the list and throws an exception as it does not check if the nextNode exists in the second FOREACH statement.
It needed tweaking to work:
MATCH(node:Post) WHERE ID(node) = 2813
OPTIONAL MATCH (user:User)-[:OWNS]->(node)
OPTIONAL MATCH (node)-[:PREV]->(nextNode:Post)
OPTIONAL MATCH (prevNode:Post)-[:PREV]->(node)
FOREACH (ith in CASE
WHEN user IS NOT NULL AND nextNode IS NOT NULL
THEN [1]
ELSE []
END | CREATE (user)-[:OWNS]->(nextNode)
)
FOREACH (ith in CASE WHEN
prevNode IS NOT NULL AND nextNode IS NOT NULL
THEN [1] ELSE []
END | CREATE (prevNode)-[:PREV]->(nextNode)
)
DETACH DELETE node

You can use combination of OPTIONAL MATCH, FOREACH and CASE:
MATCH(node:Post) WHERE ID(node) = 2749
OPTIONAL MATCH (user:User)-[:OWNS]->(node)
OPTIONAL MATCH (node)-[:PREV]->(nextNode:Post)
OPTIONAL MATCH (prevNode:Post)-[:PREV]->(node)
FOREACH (ith in CASE WHEN
NOT user IS NULL AND
NOT nextNode IS NULL
THEN [1] ELSE [] END |
CREATE (user)-[:OWNS]->(nextNode)
)
FOREACH (ith in CASE WHEN
NOT prevNode IS NULL AND
NOT nextNode IS NULL
THEN [1] ELSE [] END |
CREATE (prevNode)-[:PREV]->(nextNode)
)
DETACH DELETE node
Update: Also you can use the procedure apoc.do.when from the apoc.library for the conditional query execution.

I recreated your data set with the following query:
CREATE
(u:User {name: 'Alice'})-[:OWNS]->
(p1:Post {number: 1})-[:PREV]->
(p2:Post {number: 2})-[:PREV]->
(p3:Post {number: 3})-[:PREV]->
(p4:Post {number: 4})-[:PREV]->
(p5:Post)
As you mentioned, using OPTIONAL MATCH can result in exceptions,
something along the lines of:
Expected to find a node at prevNode but found nothing Some(NO_VALUE)
However, you can work around this, by first doing the DELETE, then passing on the value using a WITH clause and only running the CREATE if the variable introduced by the OPTIONAL MATCH clause IS NOT NULL.
MATCH (user:User)-[:OWNS]->(node)-[:PREV]->(nextNode:Post)
WHERE node.number = 1
CREATE (user)-[:OWNS]->(nextNode)
WITH node, nextNode
OPTIONAL MATCH (prevNode:Post)-[:PREV]->(node)
DETACH DELETE node
WITH prevNode, nextNode
WHERE prevNode IS NOT NULL
CREATE (prevNode)-[:PREV]->(nextNode)

Related

Is there any way to optimize this query?

I need to optimize the following query:
IF object_id('tempdb..#TAB001') IS NOT NULL
DROP TABLE #TAB001;
select *
into #TAB001
from dbo.uvw_TAB001
where 1 = 1
and isnull(COD_CUSTOMER,'') = isnull(#cod_customer,isnull(COD_CUSTOMER,''))
and isnull(TAXCODE,'') = isnull(#taxcode, isnull(TAXCODE,''))
and isnull(SURNAME,'') = isnull(#surname,isnull(SURNAME,''))
and isnull(VATCODE,'') = isnull(#vatCode,isnull(VATCODE,''))
The goal is to improve the performance of this query.
It is currently quite fast but I would like to speed it up even more.
This query has the optional parameters for which it is necessary to make a query that regardless of whether all or 1 parameter is set, returns results in the shortest possible time.
What you have here is known as a "catch-all" or "kitchen sink" query, which need a little helping hand sometimes.
Firstly, you need to get rid of those ISNULLs; they are making the query non-SARGable. Also, I would suggest getting rid of the SELECT * and limiting the query to the columns you need.
Then, finally, we can add OPTION (RECOMPILE) to the query; why is discussed in the articles I linked above. This gives you the following:
SELECT * --Replace with Column Names
INTO #TAB001 --Do you actually need to do this?
FROM dbo.uvw_TAB001
--Removed WHERE 1 = 1 as it's always true, thus pointless
WHERE (COD_CUSTOMER = #cod_customer OR #cod_customer IS NULL)
AND (TAXCODE = #taxcode OR #taxcode IS NULL)
AND (SURNAME = #surname OR #surname IS NULL)
AND (VATCODE = #vatCode OR #vatCode IS NULL)
OPTION (RECOMPILE);
Note I am assuming that when a variable (for example #cod_customer) has the value NULL you mean that the variable should be "ignored" and not matched against NULL.
If you actually want {Column} = #{Variable} including NULL then use SQL with the format below instead:
({Column} = #{Variable} OR ({Column} IS NULL AND #{Variable} IS NULL))

Qt: How to check if the entered Primary-key exist in SQLite database or not?

I am trying to check if the primary-key (entered manually by the user) exists already in the SQLite database or not (in order to decide whether to proceed with an insertion of a new record or to do an update for an existent one).
I've tried:
query.exce();
query.isEmpty();
and bellow I'm trying: guery.isNull();
However, they all give me the same result: they all say the record doesn't exist (return 0) and go to the insertion function. They return 0 even if the ref_no does exist).
Here is my code for isNull() function:
int DatabaseManager::checkRefNoExist(QString ref_no){
QSqlQuery query;
query.prepare("SELECT * FROM basic_info WHERE ref_no = :ref_no");
query.bindValue(":ref_no", ref_no);
query.exec();
if(query.isNull(ref_no.toInt())){
return 0; // whatever the ref_no is, it always comes here !!
} else {
return 1;
}
}
You are using ref_no.toInt() as column index. This does not make sense.
To check whether the query returned any result row, try to fetch the first result (with query.first() or query.next()).

Undefined index: 0 when using hook_node_insert() Drupal 7

I'm writing a custom module to insert data into database using hook_node_insert() when creating a new node. But if I left any field in the node empty without adding anything (non required field) and save the field I get the following error even though i have used isset function to check for empty fields.
Notice: Undefined index: 0 in add_customer_node_insert() in line no:5
Line no -5
$node_id = isset($node->field_id['und'])? $node->field_id['und']['0']['value']:NULL;
You only check if $node->field_id['und'] is set but not if the next part of the multi dimensinal array $node->field_id['und'][0] is set which you use for your assignment to $node_id. Change your statement to
isset($node->field_id['und']['0']['value'])
In your following code
$node_id = isset($node->field_id['und'])? $node->field_id['und']['0']['value'] : NULL;
$node->field_id['und'] is an array. You should check this by using empty() function for example like this
$node_id = !empty($node->field_id['und']) ? $node->field_id['und']['0']['value'] : NULL;
OR if you want to use isset() function
$node_id = isset($node->field_id['und']['0']['value']) ? $node->field_id['und']['0']['value'] : NULL;

Nested loop conditional

Supposed I have this table:
TDID TDLINE
F04 04-AA
F04 04-BB <-- call a function
F05 05-AA
F05 05-BB <-- call a function
F06 06-AA <-- call a function
I would like to call a function while the TDID field is not the same as the previous one. I have the code below, it works but somehow it's not perfectly works (it missed the last row):
LOOP AT lines ASSIGNING <fs1>.
IF <fs2> IS INITIAL.
<fs2> = <fs1>.
ELSE.
li_line-tdline = <fs2>-tdline.
APPEND li_line.
IF <fs1>-tdid NE <fs2>-tdid.
li_thead-tdid = <fs2>-tdid.
CALL FUNCTION 'SAVE_TEXT'
EXPORTING
header = li_thead
savemode_direct = 'X'
TABLES
lines = li_line
CLEAR: li_thead,
li_line.
FREE: li_thead,
li_line.
ENDIF.
ENDIF.
ENDLOOP.
ANSWER
Thank you to vwegert for the answer:
LOOP AT lines ASSIGNING <fs1>.
AT NEW tdid.
REFRESH li_thead.
REFRESH li_line.
li_thead-tdid = <fs1>-tdid.
APPEND li_thead.
ENDAT.
li_line-tdline = <fs1>-tdline.
APPEND li_line.
AT END OF tdid.
CALL FUNCTION 'SAVE_TEXT'
EXPORTING
header = li_thead
savemode_direct = 'X'
TABLES
lines = li_line
ENDAT.
ENDLOOP.
Assuming that the table is sorted by TDID and no field left of TDID changes more frequently than TDID:
LOOP AT lines ASSIGNING <fs1>.
AT NEW tdid.
REFRESH some_other_tab.
ENDAT.
APPEND <fs1> TO some_other_tab.
AT END OF tdid.
CALL FUNCTION ...
ENDAT.
ENDLOOP.
The unpredictability as mentioned by vwegert comes because the characters fields next to the field on which Control statement is applied are converted to asterisks(*). If you want to use these values in the control statement make sure you copy the values in a temporary table and loop on it instead of the original internal table and use the values using READ on the original internal table. Also keep in mind that control statement considers all columns to the left of the column being used in the statement for it's condition.

List menu hierarchy using SQL Server hierarchyid

I try to build a menu using the datatype hierarchyid.
I have the root node and the current selected node. now I want to list of all elements that are related wetween root and selected node AND there siblings.
I get all related elements with following sql query
DECLARE #rootNode hierarchyid, #selectedNode hierarchyid
SELECT #rootNode = MenuNode FROM CMS_Menu WHERE MenuItemID = 3;
SELECT #selectedNode = MenuNode FROM CMS_Menu WHERE MenuItemID =15;
SELECT CMS_Menu.MenuNode
FROM CMS_Menu
WHERE #selectedNode.IsDescendantOf(MenuNode) = 1 /*all related elements*/
AND MenuNode.GetLevel() >= #rootNode.GetLevel() /*nothing below root*/
Now I have to do something like MenuNode.GetAncestor(1) = result for each row in the query above.
Does anyone have an idea how to get this in a sql query?
Thanks : )
Not entirely sure I understand the question but could you not do something like the following with the WHERE clause:
WHERE #selectedNode.IsDescendantOf(MenuNode.GetAncestor(1)) = 1
Tom

Resources