How to calculate with sql queries or views - sql

I have a table
id name parentid
----------------
1 a 0
2 b 1
3 c 2
4 d 1
Now I want to calculate level with
if direct parent id count = 6 then level1,
if have 6 level1 count then level2,
if have 6 level2 count then level3, and so on
I am using SQL Server 2005 Express

You have to use sql recursion query may be this help you http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

This should do the job: Simply jump to the parent until you reach the top and count the amount of iterations.
create function dbo.CalcLevel (#ID int)
returns int
as
begin
declare #level int=0
while #ID != 0 begin
select #ID=parentID from MyTable where ID=#ID
set #level = #level + 1
if (#level = 1000) set #ID = 0 -- compensate endless loop
end
return #level
end

Related

SQL Server: how to update a column with a value that is in that column when another number in another column is >1

I have a table with the following data:
Part Comp level item_nbr
-------------------------------
abc ab 1 1
null cd 2 2
null ef 3 3
cde gh 1 4
null ij 2 5
null kl 3 6
null mn 4 7
I would like to update the nulls to the value in each level 1, so every level that is >1 is updated with the level one value.
Part Comp level
---------------------
abc ab 1
abc cd 2
abc ef 3
cde gh 1
cde ij 2
cde kl 3
cde mn 4
I am at a loss as to how to achieve this on a very large dataset. Any help would be greatly appreciated!
To explain another way,
part level
abc 1
2
3
Then the next row is populated with another part
efg 1
2
2
etc.
Further clarification:
I need the string"abc" to be filled down with the string "abc" while the column fields below are null. The next row has a string of efg and the following column fields below are null, again, those fields should be filled down with the value "efg" and so on.
The level field = 1 will always have a part number, but all the other levels report up to the level 1 part, so should be populated identically. And repeat.
Hope this makes sense.
Use an updatable CTE with window functions:
with toupdate as (
select t.*,
max(part) over (partition by itm_nbr_not_null) as new_part
from (select t.*,
max(case when part is not null then item_nbr end) over (order by item_nbr) as itm_nbr_not_null
from t
) t
)
update toupdate
set part = new_part
where part is null;
You can run the CTE to see what is happening.
well, from your question what I understand is, you need to update the null column's value until you get a not null value. and you want to continue it up to the last row of the table.
for that scenario, I created a stored procedure, where I read the value of every n-th cell if it is null I changing it with the prev. cell's value, when the cell was not null.
Approach:
create a temporary table/ table variable.
add an extra column, which is basically identity, which will help to rank the column.
iterate a loop until the maximum row is reached.
in each iteration, read the cell value for the i-th row
4.1 if it is not null put it in a temporary variable.
4.2 else, replace/update the i-th cell's value with the temporary variable
continue it, until you reached up to the last row of the table/table variable.
look at my following snippets:
create proc DemoPost
as
begin
declare #table table(serial_no int identity(1,1), name varchar(30), text varchar(30), level int)
insert #table
select Name, Text, Level from Demo
declare #max as int = (select max(serial_no) from #table)
--select #max
declare #i as int =0
declare #temp as varchar(30)
declare #text as varchar(30)
while #i < #max
begin
set #i = #i +1
set #temp = (select name from #table where serial_no = #i)
-- if #temp is not null, fetch its value, otherwise, update/replace it with
-- previously gotten not-null cell's value.
if #temp is not null
begin
set #text = (select name from #table where serial_no = #i)
end
else
begin
update #table
set name = #text where serial_no = #i
end
end
select name, text, level from #table
end
You can update it using temporary table according to the given scenario i thought item_nbr is unique in row Hope this will help
SELECT *
INTO #TEMP
FROM URTablehere
DECLARE #PRev VARCHAR(MAX)
WHILE ( SELECT COUNT(*)
FROM URTablehere
) > 0
BEGIN
DECLARE #ID INT
DECLARE #Part VARCHAR(MAX)
DECLARE #Num INT
SELECT TOP ( 1 )
#ID = level ,
#Part = Part ,
#Num = item_nbr
FROM #TEMP
IF ( #ID = 1 )
BEGIN
SELECT #PRev = #Part
END
IF ( #ID > 1
AND #Part IS NULL
)
BEGIN
UPDATE URTablehere
SET Part = #PRev
WHERE item_nbr = #Num
END
DELETE
FROM #TEMP WHERE item_nbr=#Num
END

SQL query for parent child with no relationship

I need help regarding a query that I want to create. For instance, let's say I have this table:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(2)+ Various metal products 2 1
(3)++ Other metal products 3 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
where level specifies the relationship. The records in the table are set to reproduce a tree structure. What I'm trying to do is a query which selects all the parents with children from this table that are active. If, for instance, the Is_Active column for Metallic industry products is set to 0, I don't want to display it and it's children (arious metal products and other metal products).
The same for Various metal products, if it's not active, don't display it and it's children. I tried joining with the same table or using the WITH function but sadly I can't find a solution.
A more concrete example is this. Metallic industry products becomes inactive. Then the select result should be:
Description Level Is_Active
----------------------------------------------------
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
Or let's say the child of Metallic industry products becomes inactive. The result set should be like this:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
OK, I've had a go and it isn't pretty, but see what you think. I've used WHILE loops rather than cursors to minimise the code:
create table #ordered_products
(id int identity(1,1),
grouping int default 0,
Description varchar(128),
level int,
is_active bit);
insert into #ordered_products (Description, level, is_active)
select description, level, is_active from products;
-- All rows now have an order
declare #grouping int = 0;
declare #currentid int;
declare #found bit = 1;
declare #level int;
declare #base int;
set #currentid = (select min(id) from #ordered_products);
-- Go through all the rows setting a new group each time we hit level 1
while (#found = 1)
begin
set #level = (select level from #ordered_products where id = #currentid);
if (#level = 1)
begin
set #grouping = #grouping + 1
end
update #ordered_products set grouping = #grouping where id = #currentid
set #currentid = #currentid + 1;
set #found = (select 1 from #ordered_products where id = #currentid);
end
-- For each group, set the children to be inactive if the parent is
declare #maxgroup int = (select MAX(GROUPING) from #ordered_products);
declare #currentgroup int = 1;
while (#currentgroup <= #maxgroup)
begin
begin
set #base = (select MIN(id) from #ordered_products where is_active = 0 and grouping = #currentgroup);
if (#base > 0)
begin
update #ordered_products set is_active = 0 where grouping = #currentgroup and id > #base;
end
end
set #currentgroup = #currentgroup + 1;
end
-- Output
select * from #ordered_products where is_active = 1;
drop table #ordered_products;

SQL Server: Sum of childs column (sum only until no negative value left for childs)

again i have got a small (i hope small) problem.
I have got a parent child hirarchy where one parent can have multiple childs and a child can have again multiple childs and so on.
every parent and child has a amount (value) and a parent can compensate for any missing amount of the childrens.
Here my Table:
CREATE TABLE #Test
(
ID INTEGER NOT NULL
,ParentID INTEGER
,NAME VARCHAR(20)
,value INTEGER
)
Testdata:
INSERT INTO #Test
( ID, ParentID, NAME, value )
VALUES ( 1, NULL, 'MainStore', 1 )
, ( 2, 1, 'Substore1', 3 )
, ( 3, 1, 'Substore2', 10 )
, ( 4, 2, 'Sub1Substore1', -1 )
, ( 5, 2, 'Sub1Substore2', 1 )
, ( 6, 3, 'Sub2Substore1', 10 )
To get the parentchild realationship displayed ive tried it with an CTE:
;WITH CTE
AS ( SELECT ID
,ParentID
,Name
,Value
,0 AS LEVEL
,CAST('' AS INTEGER) AS ID_Parent
FROM #Test
WHERE ParentID IS NULL
UNION ALL
SELECT child.ID
,child.ParentID
,child.Name
,child.Value
,parent.Level + 1
,parent.ID
FROM CTE parent
JOIN #Test child ON child.ParentID = parent.ID
)
As you can see Substore1 has 2 childrens (Sub1Substore1 and Sub1Substore2) Substore1 hast a value of 3, Sub1Substore1 -1 and Sub1Substore2 has 1.
Sub1Substore1 is a child of Substore1 and the parent can compensate for missing values of the childs.
My desired output should look like this:
ID ParentID Name Value LEVEL ID_Parent FreeValues
----------- ----------- -------------------- ----------- ----------- ----------- -----------
1 NULL MainStore 1 0 0 1
2 1 Substore1 3 1 1 2
3 1 Substore2 10 1 1 8
4 2 Sub1Substore1 -1 2 2 0
5 2 Sub1Substore2 1 2 2 1
6 3 Sub2Substore1 -2 2 3 0
Sadly the SQL Fiddle Website is not working for me at the moment but i will provide this sample later on SQL Fiddle.
EDIT: Rewrote whole answer due to misunderstandment of the task.
This might be solvable elegantly with common table expression, but because CTE lacks support for multiple recursive references, this task seemed to became way too complex for me to handle.
However, here's a bit less elegant solution that should do the trick for you. Note that I made an assumption that parent's ID is always smaller than it's direct childrens'. This might become an issue if you should be able to change already inserted row's parent "on-the-fly". Anyway, here you go:
--Declare temp table.
DECLARE #Temp TABLE
(
ID INTEGER NOT NULL
,ParentID INTEGER
,NAME VARCHAR(20)
,value INTEGER
,FreeValues INTEGER
,NeedFromParent INTEGER
,ChildrenNeed INTEGER
);
--Other variables
DECLARE #ID INTEGER
DECLARE #ParentID INTEGER
DECLARE #Name VARCHAR(20)
DECLARE #value INTEGER
DECLARE #FreeValues INTEGER
DECLARE #NeedFromParent INTEGER
DECLARE #ChildrenNeed INTEGER
--Loop with cursor to calculate FreeValues
DECLARE cur CURSOR FOR SELECT id, parentId, Name, Value FROM #test
ORDER BY ID DESC -- NOTE! Assumed that Parent's ID < Child's ID.
OPEN cur
FETCH NEXT FROM cur INTO #ID, #ParentID, #Name, #value
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ChildrenNeed = CASE
WHEN SUM(temp.NeedFromParent) IS NULL THEN 0
ELSE SUM(temp.NeedFromParent) END
FROM #temp temp WHERE temp.ParentID=#ID AND temp.NeedFromParent > 0
IF #ChildrenNeed IS NULL SET #ChildrenNeed = 0
IF #Value - #ChildrenNeed < 0
SET #NeedFromParent = #Value - #ChildrenNeed
ELSE
SET #NeedFromParent = 0
SET #NeedFromParent = -#NeedFromParent
IF #NeedFromParent = 0
SET #FreeValues = #value - #ChildrenNeed
ELSE
SET #FreeValues = 0
INSERT INTO #Temp
VALUES(#ID, #ParentID, #Name, #value, #FreeValues, #NeedFromParent, #ChildrenNeed)
FETCH NEXT FROM cur INTO #ID, #ParentID, #Name, #value
END
CLOSE cur;
DEALLOCATE cur;
-- Join with recursively calculated Level.
;WITH CTE
AS ( SELECT ID ,ParentID,0 AS [Level]
FROM #Test WHERE ParentID IS NULL
UNION ALL
SELECT child.ID,child.ParentID,parent.Level + 1
FROM CTE parent INNER JOIN #Test child ON child.ParentID = parent.ID
)
SELECT t1.ID, t1.ParentID, t1.Name, t1.Value, cte.[Level], t1.FreeValues
FROM CTE cte LEFT JOIN #temp t1 ON t1.ID = cte.ID
ORDER BY ID

sql how to get consecutive appearance of value

suppose I have a column 'value', which can appear multiple times in a table with another column 'result' which can be either 1 or 0. I would like to search for consecutive 1s (ie result = 1) until the count reaches 4, then I can select value. given the result sets below:
-result set a)
value Result
----- ------
A 1
A 1
A 1
A 0
-result set b)
value Result
----- ------
A 1
A 1
A 1
A 1
result set b meets the condition and therefore value A is selected. How do I go about this ? Thanks.
This is the query: (usually this query is to detect double record in a table, but probably meet your demand).
select value, result, count(value) as [Result Sum]
from #temp
where result = 1
group by value, result
having count(value) >3
This is the Result
value result Result Sum
----- ----------- -----------
A 1 4
UPDATED:
This is the data example in my temporary table (#temp)
value result
----- -----------
A 1
A 1
A 1
A 0
A 1
D 1
D 1
D 1
D 1
B 1
B 1
C 1
C 1
C 1
C 1
From The example data C and D are the valid values
Declare #temp2 table
(
value nvarchar(5)
)
declare #value nvarchar(5), #result int, #total int, #flag bit, #tempValue nvarchar(5)
DECLARE myCursor CURSOR FOR
SELECT value, result
FROM #temp
set #flag = 1
set #tempValue = ''
OPEN myCursor;
FETCH NEXT FROM myCursor into #value, #result;
WHILE ##FETCH_STATUS = 0
BEGIN
--logic here
if (#tempValue <> #value and #result = 1) or #flag = 1
begin
set #tempValue = #value
set #total = 1
set #flag = 0
end
else --#tempvalue = #value
begin
if #result = 1
set #total = #total + 1
else --#result = 0
set #flag = 1
if #total >3 --valid value has reached 4 consecutive result =1
begin
set #flag = 1
insert into #temp2 values (#value)
end
end
FETCH NEXT FROM myCursor into #value, #result;
END;
CLOSE myCursor;
DEALLOCATE myCursor;
select * from #temp2
This is the Result of the loop (table #temp2)
value
-----
D
C
(2 row(s) affected)
You can do this in a select statement. You can find groups of items in a row by using row_number() assuming you have an id. SQL tables are inherently unordered, so you need an id or creation date or something to specify the ordering. Here is the SQL:
select value
from (select t,
(row_number() over (partition by value order by id) -
row_number() over (partition by value, results order by id)
) as grp
from table t
) t
group by value, result, grp
having count(*) > 3 and result = 1;

Loop for each row

I have two tables with FOREIGN KEY([Table_ID])
Columns
ID Table_ID ActiveFlag
1 1 0
2 2 1
3 1 1
4 3 0
Sys_Tables
Table_ID Name
1 Request
2 Plan
3 Contecst
I'm writing a stored procedure that returns any column for each table.
Example Output for values ​​above
--first output table
ID Table_ID ActiveFlag
1 1 0
3 1 1
--second output table
ID Table_ID ActiveFlag
2 2 1
--third output table
ID Table_ID ActiveFlag
4 3 0
My idea is this
Select c.*
from Ccolumns c
inner join Sys_tables t
on t.Table_ID = c.Table_ID and t.Table_ID = #Parameter
My problem, i do't know how to make a loop for each row. I need the best way. Example i can use following loop:
DECLARE #i int = 0
DECLARE #count int;
select #count = count(t.Table_ID)
from Sys_tables t
WHILE #i < #count BEGIN
SET #i = #i + 1
--DO ABOVE SELECT
END
But this is not entirely correct. Example my Sys_tables such data may be
Table_ID Name
1 Request
102 Plan
1001 Contecst
Do You have any idea?
There are couple ways you can achieve that: loops and cursors, but first of all you need to know that it's a bad idea: either are very slow, anyway, here's some kind of loop sample:
declare #row_ids table (
id INT IDENTITY (1, 1),
rid INT
);
insert into #row_ids (rid) select someIdField from SomeTable
declare #cnt INT = ##ROWCOUNT
declare #currentRow INT = 1
WHILE (#currentRow <= #cnt)
BEGIN
SELECT rid FROM #row_ids WHERE id = #currentRow
SET #currentRow = #currentRow + 1
END
I guess you're using SQL Server, right?
Then, you can use a CURSOR as here: How to write a cursor inside a stored procedure in SQL Server 2008