How to call procedure for each row? - sql

I have a Microsoft SQL Server R2 2008. And i see it first time in my life.
I have sql procedure:
DECLARE #RC int
DECLARE #Id uniqueidentifier
DECLARE #Segment_ID uniqueidentifier
DECLARE #SDate datetime
DECLARE #EDate datetime
DECLARE #withBig bit
DECLARE #withKm bit
DECLARE #withGeo bit
DECLARE #withDescr bit
-- TODO: задайте здесь значения параметров.
EXECUTE #RC = [Request_BusStation]
#Id
,#Segment_ID
,#SDate
,#EDate
,#withBig
,#withKm
,#withGeo
,#withDescr
GO
How i understand its just calling of procedure not thetself. But procedure too bit to copy it here.
AND have a table:
CREATE TABLE [BusStation](
[Id] [uniqueidentifier] NOT NULL,
[Segment_ID] [uniqueidentifier] NOT NULL,
[Dist] [decimal](18, 4) NOT NULL,
[Kod_Spr012] [smallint] NOT NULL,
[Square] [decimal](18, 6) NULL,
[OperationStartDate] [date] NULL,
[BallanceCost] [decimal](18, 6) NULL,
[DepreciatedCost] [decimal](18, 6) NULL,
[ChargesNorm] [decimal](18, 6) NULL,
[DocumentName] [varchar](100) NULL,
[DocumentNum] [varchar](100) NULL,
[DocumentDate] [date] NULL,
[Authority] [varchar](100) NULL,
[Kod_Spr091] [smallint] NOT NULL,
[HasWaysideStop] [bit] NOT NULL,
[HasLanding] [bit] NOT NULL,
[HasSpeedTransitArea] [bit] NOT NULL,
[LenSpeedTransitArea] [decimal](18, 6) NULL,
[YearBuilt] [smallint] NULL,
[YearMajorOverhaul] [smallint] NULL,
[Kod_Spr019] [smallint] NOT NULL,
[TechCond] [varbinary](max) NULL,
[LandCont] [varbinary](max) NULL,
[LandContDate] [date] NULL,
[LandContStartDate] [date] NULL,
[LandContEndDate] [date] NULL,
[Kod_Spr120] [smallint] NULL,
[E_Date_Begin] [datetime] NOT NULL,
[E_Date_End] [datetime] NULL,
[E_Date_Stop] [datetime] NULL,
Now i want to call this procedure for each row of table.
Its possible?

Yes, you can use a cursor that selects all the rows in the table and iteratively calls the stored procedure.
I would suggest that you may have a design issue before going down that route though. If the stored procedure needs to be called for every row in the table, you may be able to write a stored procedure that simply does what your current sp does to all the rows instead of a single row operation.
You have not provided what the sp is doing so I can only speculate here.

As mentioned in my comment, the only way I would know how to do that is using a CURSOR. Here is some sample code (untested of course):
DECLARE #ID INT
DECLARE #Segment_ID uniqueidentifier
DECLARE #getAccountID CURSOR
SET #BusStationCursor = CURSOR FOR
SELECT Id, Segment_ID --(etc: all the fields you need)
FROM BusStation
OPEN #BusStationCursor
FETCH NEXT FROM #BusStationCursor INTO #ID, #Segment_ID
WHILE ##FETCH_STATUS = 0
BEGIN
--CALL YOUR SP HERE
PRINT #ID
PRINT #Segment_ID
FETCH NEXT FROM #BusStationCursor INTO #ID, #Segment_ID
END
CLOSE #BusStationCursor
DEALLOCATE #BusStationCursor
This should help as well:
http://msdn.microsoft.com/en-us/library/ms180169.aspx
Good luck.

Related

SQL Server export image to hardisc by iterating through fieldnames

We receive 10 images in varchar format through a mobile device app which are stored in one record of a table. The fields where the images are imported are named ImportPictureData, ImportPictureData2,...
[ID] [int] IDENTITY(1,1) NOT NULL,
[Projectnumber] [varchar](20) NULL,
[DeviceID] [nchar](20) NULL,
[Sendtime] [datetime] NULL,
[DeviceName] [nchar](30) NULL,
[ImportPictureData] [varchar](max) NULL,
[PictureData] [varbinary](max) NULL,
[ImportPictureData2] [varchar](max) NULL,
[PictureData2] [varbinary](max) NULL,
[ImportPictureData3] [varchar](max) NULL,
[PictureData3] [varbinary](max) NULL,
[ImportPictureData4] [varchar](max) NULL,
[PictureData4] [varbinary](max) NULL,
[ImportPictureData5] [varchar](max) NULL,
[PictureData5] [varbinary](max) NULL,
[ImportPictureData6] [varchar](max) NULL,
[PictureData6] [varbinary](max) NULL,
[ImportPictureData7] [varchar](max) NULL,
[PictureData7] [varbinary](max) NULL,
[ImportPictureData8] [varchar](max) NULL,
[PictureData8] [varbinary](max) NULL,
[ImportPictureData9] [varchar](max) NULL,
[PictureData9] [varbinary](max) NULL,
more of the importfields could be added.
To make the export flexible, I read the fieldnames in a table variable and try to create a dynamic SQL for the loop through the fields.
The SQL-string looks good where I create the string and print it(!) and then I try to assign the string to the variable which should recieve the image data:
set #sqlDynamicString='(Select Cast('''' AS XML).value(''xs:base64Binary(sql:column("'+ #PictureDateFieldName + '"))'', ''VARBINARY(MAX)'') FROM ScanIT_tblProjektbilder Where ID='''+ #PicID +''')'
creates this string:
(Select Cast('' AS XML).value('xs:base64Binary(sql:column("ImportPictureData"))', 'VARBINARY(MAX)') FROM ScanIT_tblProjektbilder Where ID='105')
DECLARE #ImageData VARBINARY(max);
select #ImageData = (Select Cast('' AS XML).value('xs:base64Binary(sql:column("ImportPictureData"))', 'VARBINARY(MAX)') FROM ScanIT_tblProjektbilder Where ID='105')
When I assign this string as a hardcopy to the variable #ImageData I do not get any error, if I am going to assign the variable #sqlDynamicString to the variable #ImageData like
select #ImageData = #sqlDynamicString
I get an
error 257: Implicit conversion from datatype 'VARCHAR' to 'VARBINARY(MAX)' is not allowed. Use CONVERT-Function
what is going wrong here??
Even using convert iso cast I get the same error.
Thanks
Execute the code in #sqlDynamicString,store the result in a temp table and then assign to your varbinary variable.
create table #temp
(
imageData varbinary(max)
)
insert into #temp
exec #sqlDynamicString
select #ImageData=(select imageData from #temp)

How to implement procedure to create document with header and lines in 2 different tables SQL

I'm working on an android application for inventory. It has an Sql Server Database. I have to tables like:
InventoryHeader
[id] [int] IDENTITY(1,1) NOT NULL,
[transactionumber] [varchar](30) NOT NULL,
[storeroom] [varchar](15) NULL,
[transactiontype] [varchar](15) NOT NULL,
[projectname] [varchar](50) NULL,
[projectid] [int] NULL,
[comments] [varchar](250) NULL,
[addedBy] [varchar](20) NOT NULL,
[date] [datetime] NOT NULL
Inventorylines
[id] [int] IDENTITY(1,1) NOT NULL,
[transactionumber] [varchar](30) NOT NULL,
[linenumber] [int] NOT NULL,
[storeroom] [varchar](15) NULL,
[locationtype] [varchar](10) NULL,
[storeroomlocationid] [int] NULL,
[itemnum] [varchar](20) NULL,
[quantity] [decimal](10, 3) NULL,
[uom] [varchar](10) NULL,
[unitprice] [decimal](10, 3) NULL,
[lineprice] [decimal](10, 3) NULL
Which is the best way to make an api to create a document with header and one or more lines? I managed to create a procedure to create the header of the document but not the lines. Any suggestions?
Here is the procedure I have:
`CREATE PROCEDURE [dbo].[spAddNewInventoryTr]
#Transactionumber varchar(30) ,
#Storeroom varchar(15) ,
#Transactiontype VArchar(15) ,
#Projectname VArchar(50) ,
#Comments varchar(250) ,
#Addedby varchar(20) ,
#Date datetime
AS
BEGIN
DECLARE #Projectid int
exec #Projectid = projectidproc #Projectname, #Projectid output
INSERT INTO inventoryheader(transactionumber,storeroom, transactiontype,
projectname, projectid, comments, addedBy,date)
VALUES(#Transactionumber,#Storeroom,
#Transactiontype,#Projectname,#Projectid , #Comments,#Addedby ,#Date)
END
GO`

How to update my table where updated columns names stored in another table in SQL Server

I have table User with n columns that stores user information in it.
I have another table User_Edit_Changes that I use to temporarily store changes to table User in it so that after admin confirmation I update the actual table User with new values.
In table User_Edit_Changes, I stored which user column requested for update and what is new value for that. How to write a dynamic query to get just changed value columns and new value from User_Edit_Changes and update the User table?
here is my sample create table command ,
teacher stores infos,
Tbl_ProfessorRequest stores edit change request,
Tbl_ProfessorEditInfoFields stores which fileds teacher request to edit
CREATE TABLE [dbo].[Teacher](
[code_ostad] [numeric](18, 0) NOT NULL,
[name] [varchar](30) NULL,
[family] [varchar](40) NOT NULL,
[namep] [varchar](30) NULL,
[idmadrak] [numeric](18, 0) NULL,
[namemadrak] [varchar](50) NULL,
[idresh] [numeric](18, 0) NULL,
[nameresh] [varchar](50) NULL,
[martabeh] [numeric](18, 0) NULL,
[namemartabeh] [varchar](30) NULL,
[nahveh_hamk] [numeric](18, 0) NULL,
CREATE TABLE [Request].[Tbl_ProfessorRequest](
[ProfessorRequestID] [int] IDENTITY(1,1) NOT NULL,
[Code_Ostad] [int] NULL,
[RequestTypeID] [bigint] NULL,
[RequestLogID] [bigint] NULL,
[CreateDate] [nvarchar](10) NULL,
[Note] [nvarchar](1000) NULL,
[term] [nvarchar](8) NULL,
[ProfessorMessage] [nvarchar](1000) NULL,
[Erae_Be] [nvarchar](100) NULL,
[ChangeSet] [int] NULL,
[isdeleted] [bit] NOT NULL,
[ScanImageUrl] [nvarchar](300) NULL,
CREATE TABLE [Request].[Tbl_ProfessorEditInfoFields](
[Id] [int] IDENTITY(1,1) NOT NULL,
[code_ostad] [int] NOT NULL,
[teacher_Column_Name] [nvarchar](200) NULL,
[OldValue] [nvarchar](200) NULL,
[NewValue] [nvarchar](200) NULL,
[State] [int] NOT NULL,
[ProfessorRequestID] [int] NOT NULL,
I'd say you have 3 options:
Handle the logic of updates outside the database, in what ever your application is built with. That's most likely the easiest way, since this kind of dynamic handling is not what databases are good at.
Build a dynamic SQL clause based on the contents of User_Edit_Changes. Loop through the changes in the table, construct an update statement into a variable and use sp_executesql to execute it. With cursor the code should be something like this:
set #params = N'#NewValue varchar(100)'
fetch next from yourcursor into #FieldName, #NewValue
while ##FETCH_STATUS = 0 begin
set #sql = 'update User set ' + #FieldName + ' = #NewValue'
exec sp_executesql #sql, #params, #NewValue = #NewValue
fetch next from yourcursor into #FieldName, #NewValue
end
Create static SQL statements for updating each of the columns. You can build something like this:
update U
set U.UserName = C.NewValue
from
User U
join User_Edit_Changes C on U.UserId = C.UserId
where
C.FieldName = 'UserName'
For this you of course need to have similar statements for each of your columns. You could build one massive update query with pivot or max+case, but handling the old and new values gets pretty complex.

Unable to exit Sql cursor

This is hard for me to explain but I have tried my best to make it as easy for you all as I can.
I have two tables. One stores information about customer tbl_installations. Another his internet bills tbl_bills (this one is more important).
tbl_installations
CREATE TABLE [dbo].[tbl_installations](
[SrNo] [int] IDENTITY(1000,1) NOT NULL,
[name] [varchar](200) NULL,
[email] [varchar](100) NULL,
[phone] [varchar](20) NULL,
[plandesc] [varchar](50) NULL,
[plancost] [money] NULL,
[amtpaid] [money] NULL,
[amtbalance] [money] NULL,
[address] [varchar](500) NULL,
[referencename] [varchar](20) NULL,
[installationdate] [date] NULL,
[planduration] [int] NULL,
[MkrId] [varchar](20) NULL,
[MkrDt] [datetime] NULL,
[FromDate] [datetime] NULL,
[ToDate] [datetime] NULL,
[ExpiryDate] [datetime] NULL,
[Status] [varchar](20) NULL,
[CustomerId] [varchar](20) NULL,
[ServiceTax] [money] NULL,
[TotalAmt] [money] NULL
) ON [PRIMARY]
tbl_bills
CREATE TABLE [dbo].[tbl_Bills](
[Srno] [int] IDENTITY(1,1) NOT NULL,
[CustomerId] [varchar](20) NULL,
[PlanDuration] [int] NULL,
[Amount] [money] NULL,
[PaidAmt] [money] NULL,
[discount] [money] NULL,
[PlanDesc] [varchar](20) NULL,
[FromDate] [datetime] NULL,
[ToDate] [datetime] NULL,
[MkrId] [varchar](20) NULL,
[MkrDt] [datetime] NULL,
[ServiceTax] [money] NULL,
[TotalAmt] [money] NULL,
[PendingAmt] AS ([TotalAmt]-([PaidAmt]+[discount])),
[PaidStatus] [varchar](10) NULL
) ON [PRIMARY]
THIS SCRIPT WILL GIVE YOU DATA THAT I HAVE:
insert into tbl_installations(name,email,phone,plandesc,plancost,amtpaid,amtbalance,address,referencename,installationdate,planduration,MkrId,
MkrDt,FromDate,ToDate,ExpiryDate,Status,CustomerId,ServiceTax,TotalAmt)
values('Gulzar','asdasd','3242342',null,null,null,null,'asda asd aada','ref name',GETDATE()-4,1,'arbaaz', GETDATE(),null,null,
null,'INSTALLED','C2002',null,null )
insert into tbl_bills (PlanDuration,Amount,PaidAmt,discount,PlanDesc,FromDate,ToDate,PaidStatus,MkrId,MkrDt,ServiceTax,TotalAmt,CustomerId)
values(1,800,600,0,'1MB',GETDATE()-4,DATEADD(month,1, GETDATE()-4),'PAID','Arbaaz',getdate(),800*(12.36/100),800+800*(12.36/100),'C2001')
PendingAmt in tbl_bills is a computer column which calculates the pending amount based on totalamt - (paidamt+discount)
tbl_bills.Amount is the subsription cost eg: 800
tbl_bills.TotalAmt is sum of Amount+ServiceTax
Scenario
First Month:
Customer's subsription cost(Amount) is 800
PaidAmt=600
ServiceTax=98.88
TotalAmt=898.88
PendingAmt=298.88(computed field)
Second Month:
Customer still has same subscription worth 800 (total 898.88)
But he pays 1100 so that he settles some of pending amount.
This 1100 must first settle all the previous pending amounts first(by updating tbl_bills.paidamt and then what ever is left should be inserted as a brand new row in the same table.
HERE IS MY FAILED ATTEMPT :
THIS KEEPS ON RUNNING ENDLESSLY
declare #srno as int=0
declare #Cid as varchar(20)='C2001'
declare #PlanDuration as int=1
declare #Amount as money=800
declare #PlanDesc as varchar(20)='1MB'
declare #FromDate as datetime ='2014-11-11'
declare #ToDate as datetime='2014-12-11'
declare #PaidStatus as varchar(20)
declare #MkrId as varchar(20)='arbaaz'
declare #status as varchar(20)='PAID'
declare #Discount as money=0
declare #PaidAmt as money=1100
--as
if(#status='INSTALLED')
BEGIN
insert into tbl_bills (PlanDuration,Amount,PaidAmt,discount,PlanDesc,FromDate,ToDate,PaidStatus,MkrId,MkrDt,ServiceTax,TotalAmt,CustomerId)
values(#PlanDuration,#Amount,#paidamt,#discount,#plandesc,#FromDate,#ToDate,'PAID','Arbaaz',getdate(),#Amount*(12.36/100),#Amount+#Amount*(12.36/100),#Cid)
if((select sum(PendingAmt) from tbl_Bills where CustomerId=#cid)=0 )
begin
update tbl_installations set Status='PAID' ,ExpiryDate=#ToDate where CustomerId=#Cid
end
else
begin
update tbl_installations set Status='UNPAID' ,ExpiryDate=#ToDate where CustomerId=#Cid
end
END
ELSE
BEGIN
declare #pAmt as money
select #pAmt=sum(PendingAmt) from tbl_Bills where CustomerId=#Cid
declare #Amt as money =#Amount
select #Amt=#Amt
--select srno from tbl_Bills where CustomerId=#Cid and PendingAmt<>0 order by ToDate
if(#pAmt>0)
BEGIN------------------------
DECLARE #ColExpir datetime
DECLARE #ColFallprotec datetime
DECLARE #CurSrno int
--------------------------------------------------------
DECLARE #MyCursor CURSOR
SET #MyCursor = CURSOR FAST_FORWARD
FOR
select srno from tbl_Bills where CustomerId=#Cid and PendingAmt<>0 order by todate
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #CurSrno
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#Amt>0)
BEGIN
declare #PendingAtCurSrno money
select #PendingAtCurSrno=pendingamt from tbl_Bills where SrNo=#CurSrno
print #CurSrno -----
print #PendingAtCurSrno ----
if(#Amt>#PendingAtCurSrno)
begin
update tbl_Bills set PaidAmt=TotalAmt where SrNo=#CurSrno
select #Amt=#Amt-#PendingAtCurSrno
print '1st'----
print #amt----
if(#amt=0)
begin
CLOSE #MyCursor --tried break and return here too
DEALLOCATE #MyCursor --
end
end
else
begin
update tbl_Bills set PaidAmt=paidamt+#Amt where SrNo=#CurSrno
select #Amt=0
print '2nd'
print #amt----
if(#amt=0)
begin
CLOSE #MyCursor --tried break and return here too
DEALLOCATE #MyCursor
end
end
END
END
FETCH NEXT FROM #MyCursor
INTO #PendingAtCurSrno
END
CLOSE #MyCursor
DEALLOCATE #MyCursor
END-------------------------
if(#Amt>0)
begin
insert into tbl_bills (PlanDuration,Amount,PaidAmt,discount,PlanDesc,FromDate,ToDate,PaidStatus,MkrId,MkrDt,ServiceTax,TotalAmt,CustomerId)
values(#PlanDuration,#Amount,#Amt,#discount,#plandesc,#FromDate,#ToDate,'PAID','Arbaaz',getdate(),#Amount*(12.36/100),#Amount+#Amount*(12.36/100),#Cid)
end
if((select sum(PendingAmt) from tbl_Bills where CustomerId=#cid)=0 )
begin
update tbl_installations set Status='PAID' ,ExpiryDate=#ToDate where CustomerId=#Cid
end
else
begin
update tbl_installations set Status='UNPAID' ,ExpiryDate=#ToDate where CustomerId=#Cid
end
Not only does it keep running endlessly , it keeps updating the paidamt over and over again and never gets to the point where it should insert another row with remaining amount.

SCOPE_IDENTITY() id's conflicts

I have a 3 tables UniversityReg, SupporterReg & Login. If university or supporter register with the system, always general details goes to their table & login details goes to Login table. In here I use scope_identity.
I'm getting error when I go to save supporter reg details.
Errors
Msg 515, Level 16, State 2, Procedure SupporterReg_SP, Line 16
Cannot insert the value NULL into column 'SupporterId', table 'CounsellingDB.dbo.SupporterReg'; column does not allow nulls. INSERT fails.
Msg 515, Level 16, State 2, Procedure SupporterReg_SP, Line 20
Cannot insert the value NULL into column 'LoginID', table 'CounsellingDB.dbo.Login'; column does not allow nulls. INSERT fails.
UniversityReg SP
ALTER PROCEDURE [dbo].[UniversityReg_SP]
(
#Username varchar(50),
#Password varchar(50),
#UniversityName varchar(50) ,
#GovernmentRegNo varchar(50) ,
#Country varchar(50) ,
#CreatedBy varchar(50)
)
AS
DECLARE #LoginID int
INSERT INTO UniversityReg (UniversityName,GovernmentRegNo,Country,CreatedBy,ShortCode)values(#UniversityName,#GovernmentRegNo,#Country,#CreatedBy,'UNI')
SET #LoginID = SCOPE_IDENTITY();
INSERT INTO Login values(#LoginID,#Username,#Password,'UNI')
RETURN
SupporterReg_SP
CREATE PROCEDURE [dbo].[SupporterReg_SP]
(
#UserName varchar(50),
#Password varchar(50),
#SupporterName varchar(50),
#University varchar(50) ,
#ContactNo varchar(50),
#Email varchar(50),
#StudentLocation varchar(50)
)
AS
DECLARE #LoginID int
INSERT INTO SupporterReg(SupporterName,University,ContactNo,Email,StudentLocation,ImagePath,ShortCode)V alues(#SupporterName,#University,#ContactNo,#Email,#StudentLocation,'','SUP')
SET #LoginID = SCOPE_IDENTITY();
INSERT INTO Login values(#LoginID,#UserName,#Password,'SUP')
RETURN
UniversityReg Table
[UniversityId] [int] IDENTITY(1,1) NOT NULL,
[Username] [varchar](50) NULL,
[Password] [varchar](50) NULL,
[UniversityName] [varchar](50) NULL,
[GovernmentRegNo] [varchar](50) NULL,
[Country] [varchar](50) NULL,
[CreatedBy] [varchar](50) NULL,
[ShortCode] [varchar](50) NULL,
Login Table
[LoginID] [int] NOT NULL,
[UserName] [nvarchar](50) NOT NULL,
[Password] [nvarchar](50) NOT NULL,
[ShortCode] [nvarchar](50) NULL
SupporterReg table
[SupporterId] [int] NOT NULL,
[SupporterName] [varchar](50) NULL,
[University] [varchar](50) NULL,
[ContactNo] [varchar](50) NULL,
[Email] [varchar](50) NULL,
[StudentLocation] [varchar](50) NULL,
[ImagePath] [varchar](50) NULL,
[ShortCode] [varchar](50) NULL,
In your stored procedures #LoginID is the ID for SupporterReg or UniversityReg, not for Login
In Login, your LoginID column should be defined as int identity(1,1) and you should specify column names in your insert
INSERT INTO Login (column, names, go here)
values(#LoginID,#UserName,#Password,'SUP')
Your trouble is that your procedure is attempting to insert multiple values into the SupporterReg table however you are not including a value for the SupporterID column, which has been defined a NOT NULL.
You can either pass a value along with that insert statement, or adjust the table DDL so that it's an IDENTITY column and will fill that data for you.
Your design is wrong. You should not be using the id from two different tables in the login table as the loginid. This is a model that can not work in practice as both tables will sooner or later have the same id and you won't know which one the login relates to. You have a the parent child relationship reversed.
The correct design is to insert to Login first making the loginid the identity. Then insert to the child table of either UniversityReg or SupporterReg. When you do this you can have FKs and referntial integrity.