Sql hierarchyID - finding the lowest child (last node) value - sql-server

Lets say i have this data in my db
/
/1/
/1/1/
/1/2/
/1/2/1/
/2/1/
/2/1/1/
/2/2/1/
I want to get for each row the last child within the hirarchyId
I have tried to use the getdecendent and getancestor but it wont gives me what i need
I have tried getAncestor with negative number thinking maybe it will go from the end but no luck
Is there a built in way to get the value of a specific level from hierarchyID

…
select *, h.GetReparentedValue(isnull(h.GetAncestor(1),h), hierarchyid::GetRoot()/*..or '/' */) as lastnode
from
(
values (cast('/' as hierarchyid)),('/1/'),('/1/2/'), ('/1/2/3/4/5/')
) as v(h);

Related

Multi User updates

We have a table that has reference numbers for documents. The simplified version of this table, call it RefNum, is,
id - int - identity
refN - smallint - the reference number
avail - bit - is number available (0 - is available, 1 - not available)
This table is pre-filled with refN's that have avail = 0. The reference number is available if avail is zero.
How do I write the SQL to select the next available reference number, and update it(set avail to 1), without worrying about two users getting the same number?
Can I simply wrap the SQL statements in a BEGIN / COMMIT TRANSACTION block?
I'm sure I'm over thinking this.
Thanks in advance.
I would also recommend a sequence but if you really have to use what is there then the following should work:
DECLARE #op TABLE (RefN smallint NOT NULL);
UPDATE RefNums
SET avail = 1
OUTPUT inserted.RefN
INTO #op
WHERE RefN =
(
SELECT MIN(RefN)
FROM RefNums WITH (UPDLOCK)
WHERE avail = 0
);
SELECT *
FROM #op;
use sequence for Ref number & user sequence for update
check below URL
Link : https://www.c-sharpcorner.com/blogs/create-sequence-in-sql
Sequence generate Unique number every time

XQuery Node By Value Then Its Sibling

<a>
<b>111</b>
<c>AAA</c>
<b>222</b>
<c>BBB</c>
<b>333</b>
<c>CCC</c>
</a>
The above value is found in the an XML typed column in SQL Server.
I want to find the value for node located after node with the value of "111". Can this be done using XQuery?
So far I have:
SELECT X.Y.value('('b[.="111"])[1]', 'varchar(10)') AS 'MyColumn'
FROM DBTable
CROSS APPLY DocXml.nodes('/a') AS X(Y);
This gets me the first node but I haven't been able to get the sibling.
Unfortunately SQL Server does not support sibling axes, which would have made this simpler.
Instead, you need to do the following
Save the b node into a variable using let
Take all nodes of the root by using *, filter by checking each one to see if it follows b, return the first one.
Note that you should use text() to get the inner text of a node, rather than relying on implicit conversion.
SELECT
x1.a.value('let $b := b[text() = "111"][1] return (*[. >> $b]/text())[1]','varchar(100)')
FROM DBTable t
CROSS APPLY t.DocXml.nodes('/a') x1(a);
db<>fiddle

Getting multiple values from same xml column in SQL Server

I want to get the values from same xml node under same element.
Sample data:
I have to select all <award_number> values.
This is my SQL code:
DECLARE #xml XML;
DECLARE #filePath varchar(max);
SET #filePath = '<workFlowMeta><fundgroup><funder><award_number>0710564</award_number><award_number>1106058</award_number><award_number>1304977</award_number><award_number>1407404</award_number></funder></fundgroup></workFlowMeta>'
SET #xml = CAST(#filePath AS XML);
SELECT
REPLACE(Element.value('award_number','NVARCHAR(255)'), CHAR(10), '') AS award_num
FROM
#xml.nodes('workFlowMeta/fundgroup/funder') Datalist(Element);
Can't change this #xml.nodes('workFlowMeta/fundgroup/funder'), because I'm getting multiple node values inside funder node.
Can anyone please help me?
Since those <award_number> nodes are inside the <funder> nodes, and there could be several <funder> nodes (if I understood your question correctly), you need to use two .nodes() calls like this:
SELECT
XC.value('.', 'int')
FROM
#xml.nodes('/workFlowMeta/fundgroup/funder') Datalist(Element)
CROSS APPLY
Element.nodes('award_number') AS XT(XC)
The first .nodes() call gets all <funder> elements, and then the second call goes into each <funder> element to get all <award_number> nodes inside of that element and outputs the value of the <award_number> element as a INT (I couldn't quite understand what you're trying to do to the <award_number> value in your code sample....)
Your own code was very close, but
You are diving one level to low
You need to set a singleton XPath for .value(). In most cases this means a [1] at the end)
As you want to read many <award_number> elements, this is the level you have to step down in .nodes(). Reading these element's values is easy, once you have your hands on it:
SELECT
REPLACE(Element.value('text()[1]','NVARCHAR(255)'), CHAR(10), '') AS award_num
FROM
#xml.nodes('/workFlowMeta/fundgroup/funder/award_number') Datalist(Element);
What are you trying to do with the REPLACE()?
If all <arward_number> elements contain valid numbers, you should use int or bigint as target type and there shouldn't be any need to replace non-numeric characters. Try it like this:
SELECT Element.value('text()[1]','int') AS award_num
FROM #xml.nodes('/workFlowMeta/fundgroup/funder/award_number') Datalist(Element);
If marc_s is correct...
... and you have to deal with several <funder> groups, each of which contains several <award_number> nodes, go with his approach (two calls to .nodes())

SQL Server : While loop with nested If

I'm creating a stock market database and am stumped that the following works correctly EXCEPT for the last select that returns results (after which the select does not change on subsequent loops). I've tried to simplify the code as follows, thanks in advance for feedback (I'm still noob):
Three tables:
BuyOrders
SellOrders
MatchedOrders
Stored procedure to process a NewBuyOrder:
Insert NewBuyOrder to BuyOrders;
While (NewBuyOrder.SharesRemaining > 0 )
SELECT TOP 1
FROM SellOrders
WHERE SellOrders.Price <= NewBuyOrder.Price
ORDER BY SellOrders.Price, SellOrders.TimePlaced;
IF NewBuyOrder.SharesRemaining < SellOrders.SharesAvailable
UPDATE SellOrders.SharesAvailable = [difference];
UPDATE BuyOrders = 0;
INSERT INTO MatchedOrders;
SET NewBuyOrder.SharesRemaining = 0;
BREAK;
ELSE
UPDATE SellOrders = 0;
UPDATE BuyOrders = [difference];
INSERT INTO MatchedOrders;
SET NewBuyOrder.SharesRemaining = [difference];
CONTINUE;
In hope it might help someone else, I found the issue . . . I'm using local variables to store the matched SellOrderID. As such if the Select returns no match on a second pass through then the local variables were not getting updated (and hence erroneously reused in subsequent while loops until the If kicked in).
So I put a SET SellOrders.ID = 0 into the WHILE loop before the Select then below the Select added a IF SellOrders.ID = 0 and inside that a SET NewBuyOrder.SharesRemaining = 0 and BREAK (then made the first IF above into an ELSE IF).
I need to revisit the process to see if I can make it more elegant but would sincerely welcome thoughts on better ways to accomplish a process for matching the best available counteroffers in sequence. I've read but don't know much about cursors, plus think it transactionally superior not to SELECT a prioritized table of all matches rather than using my iterative loop -- but also have read suggestions not to use loops in SQL. Comments?
In addition I note the following: By itself a Select with no results returns a null set. Thus my original plan was to Select into my SP local variables and then use an IF EXISTS. I assume the local variable exists upon instantiation (even with no value) but am surprised that after a Select into the local variable with no results also did not fail an IF NULL test (i.e. presumably NULL cannot be inserted into a variable). What then is the value of an instantiated local variable with no value -- Blank?

Getting all the ancestors doesn't work

I am using HierarchyId in SQL server and I am referring the the article below to to get all the ancestors
https://technet.microsoft.com/en-us/library/bb677212%28v=sql.105%29.aspx
I have following code:
DECLARE #last_child HIERARCHYID
select *
FROM dbo.Geography AS g
WHERE #last_child.GetAncestor(1) = 0x58
SELECT #last_child
I do have a node with id 0x58 in DB and it does have a child. However, #last_child is coming back null constantly for some reason. Am I doing anything wrong?
Ok. I am still not sure what is wrong with the code above. However, I found and alternative method to find all the children for a particular parent node. Code is posted below:
SELECT *
FROM Geography
WHERE GeographyNode.IsDescendantOf(0x58) = 1

Resources