Not able to use variable value inside CTE - sql

I am using a variable value inside a CTE but it is going into an infinite loop and when I hard code the value like 'Food' instead of variable #ProductSection, it is executing:
DECLARE #ProductSection varchar(100) = (SELECT ProductSection FROM Product WHERE ProductId = 6572);
WITH DirectIndirectProd (ProdId,ReporteeID ,NAME, [Level],[Root])
AS
(
SELECT ProdId,
ReporteeID,
NAME,
0 AS [Level] ,
RootHS AS [Root]
FROM Product
WHERE SECTION_CD = #ProductSection
UNION ALL
SELECT P1.ProdId,
P1.Report,
P1.FNAME,
[Level] + 1 , d.[Root]
FROM Product P1
INNER JOIN DirectIndirectProd AS D
ON P1.Rpt_PrdID = D.ProdID
)
Please help me in this query where I am doing wrong to declare variable value?

You would appear to have cycles in your code. That can be hard to deal with. But you can see what is happening by adding something like:
where level < 10
to see what is happening.
One trivial case would be if Rpt_PrdID = ProdID. However, there are other possibilities as well.
If this is the issue, I would advise you to ask a new question with appropriate sample data and desired results. Setting up a fiddle of some sort is also very helpful for this type of problem.

Related

SQL Server - SELECT statement with Variable and SUM() method

EDIT:
Will try to explain in more detail this time as best as I can. I tried to make the query a bit simpler thinking it would make it easier to understand but it might have been a bad move.
I'm trying to get the PK_Queue and FK_Queue_Milestone from the 1st row of my Queue table ordered by PriorityScore DESC and TimeAdded ASC
I only want to get the first row, but I was advised to not use TOP(1) because it would result to another SELECT being made to my original select.
This is the query that I have:
SELECT
#Local_PK_Queue = Q.PK_Queue,
#Local_PK_Milestone_Validate = Q.FK_Queue_Milestone
FROM dbo.Queue AS Q
INNER JOIN #Local_PKHolderTable AS P
ON Q.FK_Queue_Process = P.PK_Process
AND Q.FK_Queue_Milestone = P.PK_Milestone
AND Q.FK_Queue_QueueType = P.PK_QueueType
WHERE Q.FK_Queue_Milestone = P.PK_Milestone
AND Q.FK_Queue_Process = P.PK_Process
AND Q.Tags LIKE '%' + #Input_Tags + '%'
AND ((FK_Queue_State = 5 AND TimeDeferred < GETUTCDATE()) OR (FK_Queue_State = 1))
AND Q.FK_Queue_Robot IS NULL
AND Q.FK_Queue_QueueType = P.PK_QueueType
ORDER BY
Q.PriorityScore DESC,
Q.TimeAdded
When I try to run the query, it doesn't seem to be ordering it properly because it always gets the last row of my table.
So did some research and stumbled upon this question here.
It seems to be the same problem that I am experiencing but using MySQL instead of SQL Server.
TLDR: Want to ORDER BY Priority Score DESC and TimeAdded, but is not working properly
Well, you would write this as:
SELECT #var = PK_Test, #var2 = SUM(PriorityScore)
FROM Queue
GROUP BY PK_Test
ORDER BY SUM(PriorityScore);
This is very strange, though, because the GROUP BY presumably returns multiple rows and you presumably want only one. I might suspect that you really want to assign the variables to the highest priority scores:
SELECT TOP (1) #var = PK_Test, #var2 = SUM(PriorityScore)
FROM Queue
GROUP BY PK_Test
ORDER BY SUM(PriorityScore) DESC;

Completely Unique Rows and Columns in SQL

I want to randomly pick 4 rows which are distinct and do not have any entry that matches with any of the 4 chosen columns.
Here is what I coded:
SELECT DISTINCT en,dialect,fr FROM words ORDER BY RANDOM() LIMIT 4
Here is some data:
**en** **dialect** **fr**
number SFA numero
number TRI numero
hotel CAI hotel
hotel SFA hotel
I want:
**en** **dialect** **fr**
number SFA numero
hotel CAI hotel
Some retrieved rows would have something similar with each other, like having the same en or the same fr, I would like to retrieved rows that do not share anything similar with each other, how do I do that?
I think I’d do this in the front end code rather the dB, here’s a pseudo code (don’t know what your node looks like):
var seenEn = “en not in (''“;
var seenFr = “fr not in (''“;
var rows =[];
while(rows.length < 4)
{
var newrow = sqlquery(“SELECT *
FROM table WHERE “ + seenEn + “) and ”
+ seenFr + “) ORDER BY random() LIMIT 1”);
if(!newrow)
break;
rows.push(newrow);
seenEn += “,‘“+ newrow.en + “‘“;
seenFr += “,‘“+ newrow.fr + “‘“;
}
The loop runs as many times as needed to retrieve 4 rows (or maybe make it a for loop that runs 4 times) unless the query returns null. Each time the query returns the values are added to a list of values we don’t want the query to return again. That list had to start out with some values (null) that are never in the data, to prevent a syntax error when concatenation a comma-value string onto the seenXX variable. Those syntax errors can be avoided in other ways like having a Boolean of “if it’s the first value don’t put the comma” but I chose to put dummy ineffective values into the sql to make the JS simpler. Same goes for the
As noted, it looks like JS to ease your understanding but this should be treated as pseudo code outlining a general algorithm - it’s never been compiled/run/tested and may have syntax errors or not at all work as JS if pasted into your file; take the idea and work it into your solution
Please note this was posted from an iphone and it may have done something stupid with all the apostrophes and quotes (turned them into the curly kind preferred by writers rather than the straight kind used by programmers)
You can use Rank or find first row for each group to achieve your result,
Check below , I hope this code will help you
SELECT 'number' AS Col1, 'SFA' AS Col2, 'numero' AS Col3 INTO #tbl
UNION ALL
SELECT 'number','TRI','numero'
UNION ALL
SELECT 'hotel','CAI' ,'hotel'
UNION ALL
SELECT 'hotel','SFA','hotel'
UNION ALL
SELECT 'Location','LocationA' ,'Location data'
UNION ALL
SELECT 'Location','LocationB','Location data'
;
WITH summary AS (
SELECT Col1,Col2,Col3,
ROW_NUMBER() OVER(PARTITION BY p.Col1 ORDER BY p.Col2 DESC) AS rk
FROM #tbl p)
SELECT s.Col1,s.Col2,s.Col3
FROM summary s
WHERE s.rk = 1
DROP TABLE #tbl

Running Deduction CTE in SQL Server using declared variable

Can someone please explain to me why I am dumb? I am trying to use this result set to do a running deduction from the variable I declared below. Granted I am newer at CTE's but I figured this would have been INF easier.
DECLARE #monies AS money = 35600.00;
WITH RFRoll AS
(
SELECT
col
, value
, Amt = #monies
FROM #rfTmp
UNION ALL
SELECT
col
, value
, CASE
WHEN #monies>value then #monies-value
WHEN value<#monies then #monies-value
WHEN value>#monies then #monies-#monies
END Amt
FROM #rfTmp
WHERE
CASE
WHEN #monies>value then #monies-value
WHEN value<#monies then #monies-value
WHEN value>#monies then #monies-#monies
END >0
)
SELECT *
FROM RFRoll
This is the result get I get. It looks as if its just displaying the the current line calculation instead of the running deduction I'm trying to get at.
Ive tried various different ways and I keep running into a brick wall. I keep reverting to this current state which obviously isn't correct b/c I'm not actually using a running total variable.
So I guess my question is how do i do this using a variable? Am I actually able to reset the value recursively? I don't think so? Any insight would be greatly appreciated.
The desired out out would be this (not counting the extra fourth column)
Sorry for adding the 4th column it occurred to me that maybe I haven't truly understood the issue at hand and maybe I ought to rethink my approach. Basically I want cascading deduction up until a value is equal to 0. I have to do all the comparisons b/c a value can never be negative and I cant go over the value of the variable.
I am going to try and rework this in the meantime.
In SQL Server 2008, you can use apply or a correlated subquery. The basic structure is:
select r.*, r2.running_value
from #rftmp r outer apply
(select sum(r2.value) as running_value
from #rftmp r2
where r2.col <= r.col
) t2;
I'm not sure if this is what you want to accomplish.
Of course, in SQL Server 2012, the function is built in using a window function with order by.
I figured it out, if anyone cares
declare #monies as money = 35600.00;
WITH RFRoll as
(
SELECT
#rfTmp.*
, CASE
WHEN #monies>=value then value
WHEN value<#monies then value
WHEN value>#monies then #monies
END AS Amt
, CASE
WHEN #monies>=value then value
WHEN value<#monies then value
WHEN value>#monies then #monies
END AS ValueUsed
FROM #rfTmp WHERE [No] = 1
UNION ALL
SELECT
v.*
, RFRoll.Amt + CASE
WHEN v.value>#monies-RFRoll.Amt then #monies-RFRoll.Amt
WHEN v.value<#monies-RFRoll.Amt then v.value
WHEN #monies-RFRoll.Amt>v.value then v.value
END
, CASE
WHEN v.value>#monies-RFRoll.Amt then #monies-RFRoll.Amt
WHEN v.value<#monies-RFRoll.Amt then v.value
WHEN #monies-RFRoll.Amt>v.value then v.value
END
FROM #rfTmp v INNER JOIN RFRoll ON v.[No] = RFRoll.[No] + 1
WHERE RFRoll.Amt<#monies
)
SELECT * FROM RFRoll

How to loop through a result set and repeat the same thing until last level

I am trying to get the last layer from a product category. The twist is, the category got sub category and the last layer only have parentId of it's intimidate sub category.So I am trying to get the subcategory and then use that subcategory id to do the same thing again until it reaches to the last category. The only way to identify the last category is the linetype. So I was thinking to use while loop, but I am all confused.
For example
Declare #x Varchar(200)
Set #x = 'H506563'
Select stockCode
FROM stock
Where ParentStockCode = #x
It returns set of stockCode which will be the ParentStockCode in the next iteration and then those each will again give set of stockCodes. So this process will continue until I reach into the last level where the lineType will be S.
Is there any way to do that. Any suggestions will be helpful. Thanks
Hope this will help to understand better
The Last level which has the Part numbers -
You have not provided enough sample data. So I was not able to check the query. Query should return only stockCode's with LineType = 'S'. You should provide more sample data (not pictures) to get better help
declare #x varchar(200) = 'H506563'
;with rcte as (
select
StockCode, ParentStockCodeNo, LineType
from
stock
where
ParentStockCodeNo = #x
union all
select
b.StockCode, b.ParentStockCodeNo, b.LineType
from
rcte a
join stock b on a.StockCode = b.ParentStockCodeNo
)
select StockCode
from rcte
where LineType = 'S'
option (maxrecursion 0)

Selecting elements that don't exist

I am working on an application that has to assign numeric codes to elements. This codes are not consecutives and my idea is not to insert them in the data base until have the related element, but i would like to find, in a sql matter, the not assigned codes and i dont know how to do it.
Any ideas?
Thanks!!!
Edit 1
The table can be so simple:
code | element
-----------------
3 | three
7 | seven
2 | two
And I would like something like this: 1, 4, 5, 6. Without any other table.
Edit 2
Thanks for the feedback, your answers have been very helpful.
This will return NULL if a code is not assigned:
SELECT assigned_codes.code
FROM codes
LEFT JOIN
assigned_codes
ON assigned_codes.code = codes.code
WHERE codes.code = #code
This will return all non-assigned codes:
SELECT codes.code
FROM codes
LEFT JOIN
assigned_codes
ON assigned_codes.code = codes.code
WHERE assigned_codes.code IS NULL
There is no pure SQL way to do exactly the thing you want.
In Oracle, you can do the following:
SELECT lvl
FROM (
SELECT level AS lvl
FROM dual
CONNECT BY
level <=
(
SELECT MAX(code)
FROM elements
)
)
LEFT OUTER JOIN
elements
ON code = lvl
WHERE code IS NULL
In PostgreSQL, you can do the following:
SELECT lvl
FROM generate_series(
1,
(
SELECT MAX(code)
FROM elements
)) lvl
LEFT OUTER JOIN
elements
ON code = lvl
WHERE code IS NULL
Contrary to the assertion that this cannot be done using pure SQL, here is a counter example showing how it can be done. (Note that I didn't say it was easy - it is, however, possible.) Assume the table's name is value_list with columns code and value as shown in the edits (why does everyone forget to include the table name in the question?):
SELECT b.bottom, t.top
FROM (SELECT l1.code - 1 AS top
FROM value_list l1
WHERE NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code = l1.code - 1)) AS t,
(SELECT l1.code + 1 AS bottom
FROM value_list l1
WHERE NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code = l1.code + 1)) AS b
WHERE b.bottom <= t.top
AND NOT EXISTS (SELECT * FROM value_list l2
WHERE l2.code >= b.bottom AND l2.code <= t.top);
The two parallel queries in the from clause generate values that are respectively at the top and bottom of a gap in the range of values in the table. The cross-product of these two lists is then restricted so that the bottom is not greater than the top, and such that there is no value in the original list in between the bottom and top.
On the sample data, this produces the range 4-6. When I added an extra row (9, 'nine'), it also generated the range 8-8. Clearly, you also have two other possible ranges for a suitable definition of 'infinity':
-infinity .. MIN(code)-1
MAX(code)+1 .. +infinity
Note that:
If you are using this routinely, there will generally not be many gaps in your lists.
Gaps can only appear when you delete rows from the table (or you ignore the ranges returned by this query or its relatives when inserting data).
It is usually a bad idea to reuse identifiers, so in fact this effort is probably misguided.
However, if you want to do it, here is one way to do so.
This the same idea which Quassnoi has published.
I just linked all ideas together in T-SQL like code.
DECLARE
series #table(n int)
DECLARE
max_n int,
i int
SET i = 1
-- max value in elements table
SELECT
max_n = (SELECT MAX(code) FROM elements)
-- fill #series table with numbers from 1 to n
WHILE i < max_n BEGIN
INSERT INTO #series (n) VALUES (i)
SET i = i + 1
END
-- unassigned codes -- these without pair in elements table
SELECT
n
FROM
#series AS series
LEFT JOIN
elements
ON
elements.code = series.n
WHERE
elements.code IS NULL
EDIT:
This is, of course, not ideal solution. If you have a lot of elements or check for non-existing code often this could cause performance issues.