how can i restart this cursor after if condition and want row_number start from one again in answer.want to restart cursor from end point of if condition.
declare #SUM DECIMAL(20,2)
declare #EMPCODE varchar(10)
declare #NETPAY DECIMAL(10,2)
declare ABC scroll cursor for
select EMPCODE,NETPAY from TXXL where DATE='04-30-2015'
open ABC
declare #TEMP table(
EMPCODE varchar(10) primary key,
NETPAY DECIMAL(10,2),
SUM varchar(max)
)
set #SUM=0
fetch first from ABC into #EMPCODE,#NETPAY
while ##fetch_status=0
begin
fetch next from ABC into #EMPCODE,#NETPAY
SET #SUM=#SUM+#NETPAY
if(#SUM<=900000)
insert into #TEMP(EMPCODE,NETPAY,SUM) values(#EMPCODE,#NETPAY,#SUM)
end
select ROW_NUMBER() OVER(ORDER BY EMPCODE) ROWNUMBER,EMPCODE,NETPAY,SUM from #TEMP
close ABC
deallocate ABC
this cursor gives that answer,cursor stop working after 000179 EMPCODE because the sum of next empcode is greater than 900000 i want to start next empcode with ROWnumber 1 and sum like that the sum of this sample :-
ROWNUMBER EMPCODE NETPAY SUM
1 000066 29079.00 29079.00
2 000076 34515.00 63594.00
3 000084 15493.00 79087.00
4 000090 30399.00 109486.00
5 000109 25812.00 135298.00
6 000111 31453.00 166751.00
7 000113 30408.00 197159.00
8 000116 28040.00 225199.00
9 000124 27901.00 253100.00
10 000128 24445.00 277545.00
11 000131 35760.00 313305.00
12 000141 23345.00 336650.00
13 000150 48965.00 385615.00
14 000179 39350.00 424965.00
want answer like that:-
ROWNUMBER EMPCODE NETPAY SUM
1 000066 29079.00 29079.00
2 000076 34515.00 63594.00
3 000084 15493.00 79087.00
4 000090 30399.00 109486.00
5 000109 25812.00 135298.00
6 000111 31453.00 166751.00
7 000113 30408.00 197159.00
8 000116 28040.00 225199.00
9 000124 27901.00 253100.00
10 000128 24445.00 277545.00
11 000131 35760.00 313305.00
12 000141 23345.00 336650.00
13 000150 48965.00 385615.00
14 000179 39350.00 424965.00
1 000181 40814.00 40814.00
2 000182 24335.00 65149.00
3 000196 29439.00 94588.00
4 ----- ------ -------
5 -------- ----- -------
Related
I am looking for a clean solution to perform calculation from a single column with a few conditions and insert it in the same table. My existing solution is to use a while loop with many variable declarations, writing simple query to store value, perform calculation and finally insert it as a new row to the table. However it looks messy and complicated. I am wondering if there is a better solution to it?
Original Table
Week | Indicator | Value
1 A 2
1 B 3
1 D 10
1 E 5
1 X 12
1 Y 6
2 A 4
2 B 5
2 D 7
2 E 3
2 X 4
2 Y 2
...
53
Updated Table
Week | Indicator | Value
1 A 2
1 B 3
1 C 5
1 D 10
1 E 5
1 F 5
1 X 12
1 Y 6
1 Z 2
2 A 4
2 B 5
2 C 9
2 D 7
2 E 3
2 F 4
2 X 4
2 Y 2
2 Z 2
In this example in the updated table, every 3rd row involves different calculation for the same week such that the 3rd row is an addition, 6th row is a subtraction and the 9th row is a division.
The calculation does not restrict to only addition and could include other forms of calculation formulas. I am just using addition as a simple illustration.
Here is an example of my SQL solution:
DECLARE #total_rows int;
SET #total_rows = (SELECT COUNT(*) FROM original_table);
DECLARE #wk varchar(5);
DECLARE #indicator1 char(1);
DECLARE #indicator2 char(1);
SET #indicator1 = 'A';
SET #indicator2 = 'B';
DECLARE #a_value int;
DECLARE #b_value int;
DECLARE #cal_value int;
DECLARE #iteration int
SET #iteration = 1
WHILE #iteration <= #total_rows
BEGIN
IF #iteration <= 53
SET #wk = concat('W',#iteration)
SET #a_value = (SELECT value
FROM original_table
WHERE indicator = #indicator1 and week = #wk);
SET #b_value = (SELECT value
FROM original_table
WHERE indicator = #indicator2 and week = #wk);
SET #cal_value = (#a_value/ NULLIF(#b_value,0)) *1000000;
....
SET #iteration = #iteration + 1
END
Not going to post the entire SQL script as it is quite lengthy but I hope you get the gist of it.
Is this not as simple as INSERT and SUM..?
INSERT INTO dbo.YourTable ([Week],Indicator,[Value])
SELECT YT.[Week],
'C' AS Indicator,
SUM(YT.[Value]) AS [Value]
FROM dbo.YourTable YT
GROUP BY YT.[Week];
DB<>Fiddle
I have some specific values I want to extract out of a string in SQL Server, but I'm not sure exactly how to get it done with PATINDEX.
Take this string:
declare #Command nvarchar(500) = 'IF dbo.SomeFunctionFn() = 1 BEGIN EXEC SomeStoredProcPR #RowsPerRun=500000, #RowsPerBatch=10000, #NbrDaysToKeepRpt=7 END'
I want to extract out the values of 500000 (for #RowsPerRun), 10000 for #RowsPerBatch and the value of 7 for #NbrDaysToKeepRpt. The values will be of variable length, so I can't guarantee the #RowsPerRun value will be 6 characters.
Is that possible?
DECLARE #Command NVARCHAR(500) =
'IF dbo.SomeFunctionFn() = 1 BEGIN EXEC SomeStoredProcPR #RowsPerRun=500000, #RowsPerBatch=10000, #NbrDaysToKeepRpt=7 END'
SELECT
SearchItem = srch.Txt,
ItemIndex = st.Pos,
ItemLen = t.Ln,
Item = SUBSTRING(pfx.Txt,1,t.Ln)
FROM (VALUES('#RowsPerRun='),('#RowsPerBatch='),('#NbrDaysToKeepRpt=')) AS srch(Txt)
CROSS APPLY (VALUES(CHARINDEX(srch.Txt,#Command),LEN(srch.Txt))) AS st(Pos,Ln)
CROSS APPLY (VALUES(SUBSTRING(#Command, st.Pos+st.Ln, 500))) AS pfx(Txt)
CROSS APPLY (VALUES(PATINDEX('%[^0-9]%',pfx.Txt)-1)) AS t(Ln);
Returns:
SearchItem ItemIndex ItemLen Item
------------------ ----------- ----------- --------
#RowsPerRun= 59 6 500000
#RowsPerBatch= 79 5 10000
#NbrDaysToKeepRpt= 100 1 7
Note that I included a few extra columns to help you understand what's happening.
Update: Against a table
This is how you would apply this logic to a series of values:
DECLARE #sometable TABLE (CommandId INT IDENTITY, Command NVARCHAR(500));
INSERT #sometable (Command)
VALUES
('IF dbo.SomeFunctionFn() = 1 BEGIN EXEC SomeStoredProcPR #RowsPerRun=500000, #RowsPerBatch=10000, #NbrDaysToKeepRpt=7 END'),
('IF dbo.SomeFunctionFn() = 5 BEGIN EXEC SomeStoredProcPR #RowsPerRun=123, #RowsPerBatch=500, #NbrDaysToKeepRpt=20 END'),
('IF dbo.SomeFunctionFn() = 5 BEGIN EXEC XXX #RowsPerRun=43, #RowsPerBatch=1000, #NbrDaysToKeepRpt=120 END'),
('IF dbo.SomeFunctionFn() = 5 BEGIN EXEC abc.yyy #RowsPerRun=43, #RowsPerBatch=1000, #NbrDaysToKeepRpt=120 END');
SELECT t.CommandId, f.SearchItem, f.Item
FROM #sometable AS t
CROSS APPLY
(
SELECT
SearchItem = srch.Txt,
ItemIndex = st.Pos,
ItemLen = t.Ln,
Item = SUBSTRING(pfx.Txt,1,t.Ln)
FROM (VALUES('#RowsPerRun='),('#RowsPerBatch='),('#NbrDaysToKeepRpt=')) AS srch(Txt)
CROSS APPLY (VALUES(CHARINDEX(srch.Txt,t.Command),LEN(srch.Txt))) AS st(Pos,Ln)
CROSS APPLY (VALUES(SUBSTRING(t.Command, st.Pos+st.Ln, 500))) AS pfx(Txt)
CROSS APPLY (VALUES(PATINDEX('%[^0-9]%',pfx.Txt)-1)) AS t(Ln)
) AS f;
Returns:
CommandId SearchItem Item
----------- ------------------ --------
1 #RowsPerRun= 500000
1 #RowsPerBatch= 10000
1 #NbrDaysToKeepRpt= 7
2 #RowsPerRun= 123
2 #RowsPerBatch= 500
2 #NbrDaysToKeepRpt= 20
3 #RowsPerRun= 43
3 #RowsPerBatch= 1000
3 #NbrDaysToKeepRpt= 120
4 #RowsPerRun= 43
4 #RowsPerBatch= 1000
4 #NbrDaysToKeepRpt= 120
My problem is, to order these results in such a way that the order is as it is marked gray.
That is to say to obtain every first difference of the column EjeY.
Might be you are looking for this:
DECLARE #Dummy TABLE(ID INT IDENTITY, EjeY VARCHAR(100),Valor INT);
INSERT INTO #Dummy VALUES
('Alta/Deviciente',14)
,('Baja/Baja',16)
,('Baja/Media',14)
,('Alta/Alta',8)
,('Alta/Baja',12)
,('Baja/Deviciente',18)
,('Baja/Alta',12)
,('Alta/Optima',6)
,('Alta/Media',10)
,('Baja/Optima',10);
SELECT *
FROM #Dummy AS d
ORDER BY LEFT(EjeY,CHARINDEX('/',EjeY)-1),Valor DESC
The result
ID EjeY Valor
1 Alta/Deviciente 14
5 Alta/Baja 12
9 Alta/Media 10
4 Alta/Alta 8
8 Alta/Optima 6
6 Baja/Deviciente 18
2 Baja/Baja 16
3 Baja/Media 14
7 Baja/Alta 12
10 Baja/Optima 10
If you only want to record the changes in the left part of your Ejey delimited field then you need to split the field and then order rank the values by ID.
After you have a ranking you can select the records you are interested in taking the first row of the PARTITION.
DECLARE #Dummy TABLE(ID INT, EjeY VARCHAR(100),Valor INT);
INSERT INTO #Dummy VALUES
(1,'Alta/Deviciente',14)
,(2,'Alta/Baja',12)
,(6,'Baja/Optima',10)
,(7,'Baja/Alta',12)
,(11,'Deficiente/Deficiente',20)
,(11,'Deficiente/Baja',18)
,(16,'Media/Alta',10)
,(17,'Media/Optima',8)
--This query will draw a rank in your data based on the LEFT() partition of your Ejey field value.
SELECT
*,
RowNumber=ROW_NUMBER() OVER(PARTITION BY SortPart ORDER BY ID DESC)
FROM
(
SELECT
ID,
SortPart=LEFT(EjeY,CHARINDEX('/',EjeY)-1),
Valor
FROM
#Dummy
)AS X
--This query will further order only the records within your ideal set of data
SELECT
*
FROM
(
SELECT
*,
RowNumber=ROW_NUMBER() OVER(PARTITION BY SortPart ORDER BY ID ASC)
FROM
(
SELECT
ID,
SortPart=LEFT(EjeY,CHARINDEX('/',EjeY)-1),
Valor
FROM
#Dummy
)AS X
)AS Y
WHERE
RowNumber=1
--Results A
ID SortPart Valor RowNumber
2 Alta 12 1
1 Alta 14 2
7 Baja 12 1
6 Baja 10 2
11 Deficiente 20 1
11 Deficiente 18 2
17 Media 8 1
16 Media 10 2
--Results B
ID SortPart Valor RowNumber
1 Alta 14 1
6 Baja 10 1
11 Deficiente 20 1
I have 4 tables Position, Employee, Training and Trmatrix.
Table Position
PositionId PosName TrainingId
1 developer 1,2,3
2 Designer 4,5
3 BDA 2,3,6
Table Employee
Employeeid Ename Posid Courseid
1 Alex 1 4
2 Shaun 2 1,2,3
3 Hales 3
Table Training
Trainingid Trainingname
1 JAVA
2 Dot Net
3 PHP
4 Photoshop
5 JQUERY
6 Client Handling
TrMatrix
TrmatId TrID empID
1 1 1
2 2 1
3 3 1
4 4 1
5 4 2
6 5 2
7 1 2
8 2 2
9 2 3
10 3 3
foreign Key relation
trmatrix trId corresponds to the trainingID of the trainingtable.
Employee posid corresponds to the PositionId of the Positiontable.
Employee courseId corresponds to the trainingId of the trianingtable.
BY basic Aim is to get that course/trainingname which is no present in the
EMployee.Courseid column in correspondance to the trmatrix table,
which defines that I have to get the all entries from the trmatrix table for which there is no entry in the employee table Courseid column.
Suppose in case of Alex I have to fetch all the data from the trmatrix table except for course 4 since it is present in the courseid column of the Employee table, so it would return course no 1,2,3 not the no 4.
I am Newbie to the SQL so please help me out with this problem.
Thanks in advance
To start with, you should make PositionTraining and EmployeeCourse tables as well:
PositionTraining
PositionId TrainingId
1 1
1 2
1 3
2 4
2 5
3 2
3 3
3 6
EmployeeCourse
Employeeid Courseid
1 4
2 1
2 2
3 3
and then remove Position.TrainingId and Employee.Courseid.
By doing this you make the data much easier to query.
To get things which are not present in one table from another you can use
WHERE NOT EXISTS (SELECT value FROM OtherTable)
or
WHERE NOT IN (SELECT value FROM OtherTable)
However there is a class of queries called subqueries and these are very useful in this circumstance and a very good article on them is here
http://allenbrowne.com/subquery-01.html
(its written for ms access but the synstax and MS SQL rules are exactly the same so dont be put off)
UDF for spliting out entries
Create function [dbo].[atf_BarListToTable]
(#list ntext)
RETURNS #tbl TABLE (ListPosn int IDENTITY(1, 1) NOT NULL,
SString VARCHAR(1028) NOT NULL) AS
BEGIN
DECLARE #pos int
DECLARE #textpos int
DECLARE #ChunkLength smallint
DECLARE #str nvarchar(4000)
DECLARE #tmpstr nvarchar(4000)
DECLARE #leftover nvarchar(4000)
SET #textpos = 1
SET #leftover = ''
WHILE #textpos <= datalength(#list) / 2
BEGIN
SET #ChunkLength = 4000 - datalength(#leftover) / 2
SET #tmpstr = ltrim(#leftover + substring(#list, #textpos, #ChunkLength))
SET #textpos = #textpos + #ChunkLength
SET #pos = charindex('|', #tmpstr)
WHILE #pos > 0
BEGIN
SET #str = substring(#tmpstr, 1, #pos - 1)
INSERT #tbl (SString) VALUES( #str)
SET #tmpstr = ltrim(substring(#tmpstr, #pos + 1, len(#tmpstr)))
SET #pos = charindex('|', #tmpstr)
END
SET #leftover = #tmpstr
END
IF ltrim(rtrim(#leftover)) <> ''
INSERT #tbl (SString) VALUES(#leftover)
RETURN
END
I am seeking guidance using MS SQL cursor or SQL while loop to merge (add, update, and set inactive) rows using single table based on criteria below resulting in seeking the final dataset:
TABLE VIEW (SELECT * FROM TABLE WHERE ENTITY = 123 (#ID)
ENTITY ENTITY_TYPE VALUE STATUS_TYPE
123 1 1 1
123 1 4 1
123 1 9 1
TABLE VIEW (SELECT * FROM TABLE WHERE ENTITY = 456 (#OverrideID)
ENTITY ENTITY_TYPE VALUE STATUS_TYPE
456 1 1 1
456 1 5 1
Final Data Set below:
ENTITY   TYPE VALUE STATUS_TYPE
123 1 1 3
123 1 4 3
123 1 9 3
456 1 1 1
456 1 4 1
456 1 9 1
456 1 1 1
456 1 5 1
-- Check and compare each row
-- IF #OverrideID = #ID (MATCH)
----- Set #ID to inactive keeping copy
-- If #OverrideID != #ID (NOT MATCH)
----- Insert #ID data with #OverrideID (COPY)
----- Set #ID to inactive.
I began writing the following and need help. For reference, #ID = 123 and #OverrideID = 456
DECLARE #ENTITY BIGINT, #ENTITY_TYPE BIGINT, #VALUE BIGINT, #E1 BIGINT, #T1 BIGINT, #V1 BIGINT
DECLARE type_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT * FROM TypeValue WHERE ENTITY = #ID
SET NOCOUNT OFF
OPEN type_cursor
FETCH NEXT FROM type_cursor INTO #OverrideID, #ID, #ENTITY, #ENTITY_TYPE, #VALUE
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #ENTITY, #ENTITY_TYPE, #VALUE
IF #VALUE IS NOT NULL
BEGIN
SELECT #T1 = #ENTITY_TYPE, #V1 = #VALUE
END
ELSE
BEGIN
UPDATE TypeValue
SET ENTITY = #OverrideID, ENTITY_TYPE = #T1, VALUE = #V1 WHERE ENTITY = #ID
END
FETCH NEXT FROM type_cursor INTO #OverrideID, #ID, #ENTITY, #ENTITY_TYPE, #VALUE
END
CLOSE type_cursor
DEALLOCATE type_cursor
SET NOCOUNT OFF
That final result set looks like
select entity,entity_type,value,3 status_type
from [table]
where entity = #id
union all
select #override,entity_type,value,status_type
from [table]
where entity = #id
union all
select entity,entity_type,value,status_type
from [table]
where entity = #override