I use SQL Server 2012. I have a sample table named 'Table1' with seven columns.
CREATE TABLE TABLE1
(
Field1 INT ,
Field2 INT ,
Field3 INT ,
Field4 INT ,
Field5 INT ,
Field6 INT ,
Field7 INT
)
GO
INSERT INTO TABLE1 VALUES (1,2,9,5,1,5,85)
INSERT INTO TABLE1 VALUES (2,6,8,4,1,4,45)
INSERT INTO TABLE1 VALUES (3,5,7,3,5,6,1)
INSERT INTO TABLE1 VALUES (4,4,6,1,51,4,1)
INSERT INTO TABLE1 VALUES (5,5,5,4,7,2,7)
INSERT INTO TABLE1 VALUES (6,5,4,6,4,7,8)
INSERT INTO TABLE1 VALUES (7,12,5,3,2,5,3)
INSERT INTO TABLE1 VALUES (8,1,6,5,9,5,1)
INSERT INTO TABLE1 VALUES (9,1,13,2,1,7,3)
INSERT INTO TABLE1 VALUES (10,6,9,3,6,2,6)
INSERT INTO TABLE1 VALUES (11,2,1,2,8,7,7)
INSERT INTO TABLE1 VALUES (12,7,6,1,3,3,2)
INSERT INTO TABLE1 VALUES (13,7,2,6,4,7,1)
GO
I have created the below Stored Procedure, This SP is able to query data considering the asked order by column.
I can query my table with each possibility of single column and kind of order by (ASC or Desc).
CREATE Procedure ProceName
(
#OrderByField INT = 1,
#OrderDirection INT = 0 -- 0 = Asc , 1 = Desc
)
As
Begin
SELECT
*
FROM Table1
ORDER BY
CASE WHEN #OrderDirection=0 AND #OrderByField=1 THEN Field1 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=2 THEN Field2 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=3 THEN Field3 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=4 THEN Field4 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=5 THEN Field5 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=6 THEN Field6 END ASC,
CASE WHEN #OrderDirection=0 AND #OrderByField=7 THEN Field7 END ASC,
CASE WHEN #OrderDirection=1 AND #OrderByField=1 THEN Field1 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=2 THEN Field2 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=3 THEN Field3 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=4 THEN Field4 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=5 THEN Field5 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=6 THEN Field6 END DESC,
CASE WHEN #OrderDirection=1 AND #OrderByField=7 THEN Field7 END DESC End
GO
EXECUTE ProceName #OrderByField=1, #OrderDirection=0
EXECUTE ProceName #OrderByField=6, #OrderDirection=1
Now I need to change this sp for accepting multi columns as order by series columns. They can be pass by name or by order of columns.
In this case i should be able to execute my SP like below command:
EXECUTE ProceName #OrderByField='6,7,2', #OrderDirection='0,1,1'
How can I achive this gool with out using the sp_executesql (Dynamic Query)?
Well, your ascending and descending wouldn't matter in your case unless you were trying to choose asc and desc for each column. Here is using the last column.
DECLARE #OrderByField VARCHAR(64) = '1,3,7'
DECLARE #DynamicColumns VARCHAR(256) = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#OrderByField,1,'FIELD1'),2,'FIELD2'),3,'FIELD3'),4,'FIELD4'),5,'FIELD5'),6,'FIELD6'),7,'FIELD7')
DECLARE #OrderDirection INT = 1
DECLARE #order varchar(4)
SET #order = CASE WHEN #OrderDirection = 1 THEN 'DESC' ELSE 'ASC' END
--uncomment this line of code to add the sort to every column which only matters for DESC since ASC is default
--SET #DynamicColumns = REPLACE(#DynamicColumns,',', ' ' + #order + ',')
DECLARE #sql VARCHAR(MAX) = (
'SELECT
*
FROM Table1
ORDER BY ' + #DynamicColumns + ' ' + #order)
SELECT #sql
EXEC(#sql)
CREATE Procedure ProceName
(
#OrderByField VARCHAR(100),
#OrderDirection VARCHAR(100),
)
As
Begin
Declare #SQL VARCHAR(MAX)
if OBJECT_ID('Example1') is not null
begin
drop table Example
end
if OBJECT_ID('Example2') is not null
begin
drop table Example2
end
Create table Example1
(
id int identity(1,1),
Field varchar(20)
)
Create table Example2
(
id int identity(1,1),
OrderNumber varchar(10)
)
--iterate each element for both #OrderByField and #OrderDirection
Declare #separator char(1)=','
Declare #position int = 0
Declare #name varchar(20)
Set #OrderByField = #OrderByField + #separator
---------------------------------------------------------------------------
/*iterate each for #OrderByField */
---------------------------------------------------------------------------
While CHARINDEX (#separator,#OrderByField,#position) != 0
BEGIN
SET #name = SUBSTRING (#OrderByField,#position,CHARINDEX (#separator,#OrderByField,#position)-#position)
SET #SQL = 'Insert into Example1([Field]) Values(' + char(39) + #name + char(39) + ')'
EXEC(#SQL)
SET #position = CHARINDEX(#separator,#OrderByField,#position)+1
END
---------------------------------------------------------------------------
/*iterate each for #OrderDirection */
---------------------------------------------------------------------------
SET #position = 0 --do not forget to reset the position number
Set #OrderDirection = #OrderDirection + #separator
While CHARINDEX (#separator,#OrderDirection,#position) != 0
BEGIN
SET #name = SUBSTRING (#OrderDirection,#position,CHARINDEX (#separator,#OrderDirection,#position)-#position)
SET #SQL = 'Insert into Example2([OrderNumber]) Values(' + char(39) + #name + char(39)+ ')'
EXEC(#SQL)
SET #position = CHARINDEX(#separator,#OrderDirection,#position)+1
END
Set #name = '' --reset the #name for the use of Cursor
declare #NewName varchar(500) =''
Declare row_cursor CURSOR
FOR
select 'Field'+a.Field + ' '+ case when b.OrderNumber = 0 then 'ASC' else 'DESC' end +',' as command
from Example1 as a
inner join Example2 as b
on b.id = a.id
OPEN row_cursor
FETCH NEXT FROM row_cursor into #name
WHILE (##FETCH_STATUS =0)
begin
Set #NewName = #NewName + #name
FETCH NEXT FROM row_cursor into #name
end
close row_cursor
deallocate row_cursor
SET #NewName = REVERSE(STUFF(REVERSE(#NewName),1,1,''))
SET #SQL = 'Select * From Table1 Order by ' + #NewName
--Print(#SQL)
EXEC (#SQL)
END
Related
I have a query that takes start and end year for data also it takes a name of a table as procedure parameters..
the query then will create a table with that name if it doesn't exist or if exist it will drop and recreate it
CREATE OR REPLACE Procedure USE_RAWDATA
( START_RP IN NUMBER, END_RP IN NUMBER,TABLE_NAME varchar)
IS
v_listStr CLOB;
DAT VARCHAR(500):=to_char(to_date(SYSDATE), 'yyyymmdd');
cnt NUMBER;
BEGIN
BEGIN
SELECT COUNT(*) INTO cnt FROM user_tables WHERE table_name = TABLE_NAME||'_'||DAT;
dbms_output.put_line(TABLE_NAME||'_'||DAT);
dbms_output.put_line(cnt);
IF (cnt) = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE '||TABLE_NAME||'_'||DAT;
dbms_output.put_line('DROP TABLE '||TABLE_NAME||'_'||DAT);
END IF;
END;
select rtrim(xmlagg(xmlelement(e,column_name,', ').extract('//text()') order by column_id).getclobval(),', ') x INTO v_listStr from RAW_DATA_METADATA WHERE (START_ROUND<= END_RP and END_ROUND is NULL) or (START_ROUND >= START_RP and END_ROUND <= END_RP );
EXECUTE IMMEDIATE 'CREATE TABLE '||TABLE_NAME||'_'||DAT||' AS SELECT '||v_listStr ||' FROM RAW_DATA WHERE ROUND_ID BETWEEN '||START_RP ||' AND '||END_RP;
END;
/
my problem is that cnt is always giving me 0 even the table exists then the procedure will end with an error table already exist...
I don't know why .. since when I try it as PL\SQL query it gives me a correct result cnt =1 if exist
declare
v_listStr CLOB;
DAT VARCHAR(500):=to_char(to_date(SYSDATE), 'yyyymmdd');
cnt NUMBER;
BEGIN
BEGIN
SELECT COUNT(*) INTO cnt FROM user_tables WHERE :TABLE_NAME = :TABLE_NAME||'_'||DAT;
dbms_output.put_line(:TABLE_NAME||'_'||DAT);
dbms_output.put_line(cnt);
IF (cnt) = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE '||:TABLE_NAME||'_'||DAT;
dbms_output.put_line('DROP TABLE '||:TABLE_NAME||'_'||DAT);
END IF;
END;
select rtrim(xmlagg(xmlelement(e,column_name,', ').extract('//text()') order by column_id).getclobval(),', ') x INTO v_listStr from RAW_DATA_METADATA WHERE (START_ROUND<= :END_RP and END_ROUND is NULL) or (START_ROUND >= :START_RP and END_ROUND <= :END_RP );
EXECUTE IMMEDIATE 'CREATE TABLE '||:TABLE_NAME||'_'||DAT||' AS SELECT '||v_listStr ||' FROM RAW_DATA WHERE ROUND_ID BETWEEN '||:START_RP ||' AND '||:END_RP;
END;
/
can you help me figure out why it always cnt gives 0 even the table is exist
This query can only ever return 0:
select count(*) into cnt
from user_tables
where table_name = table_name || '_' || dat;
You need to either prefix table_name with the procedure name
select count(*) into cnt
from user_tables
where table_name = use_rawdata.table_name || '_' || dat;
or else name your parameters differently (tableName, p_table_name etc).
I'd also suggest removing the first begin and end as they aren't doing anything, and adjusting your indentation to reflect the code structure more accurately.
I make it something like this:
create or replace procedure use_rawdata
( start_rp in number
, end_rp in number
, table_name varchar2 )
is
v_liststr clob;
dat varchar2(8) := to_char(sysdate, 'yyyymmdd');
cnt number;
begin
select count(*) into cnt
from user_tables
where table_name = upper(use_rawdata.table_name) || '_' || dat;
dbms_output.put_line(table_name || '_' || dat);
dbms_output.put_line(cnt);
if cnt = 1 then
execute immediate 'DROP TABLE ' || table_name || '_' || dat;
dbms_output.put_line('DROP TABLE ' || table_name || '_' || dat);
end if;
select rtrim(xmlagg(xmlelement(e, column_name, ', ').extract('//text()') order by column_id).getclobval(), ', ') x
into v_liststr
from raw_data_metadata
where (start_round <= end_rp and end_round is null)
or (start_round >= start_rp and end_round <= end_rp);
execute immediate 'create table ' || table_name || '_' || dat || ' as select ' || v_liststr || ' from raw_data where round_id between ' || start_rp || ' and ' || end_rp;
end;
Good morning,
I'm having troubles to integrate a working query into a stored procedure.
My main issue, is that I'm using a WHILE loop with an integer, and that the stored procedure is having troubles with it.
My working query/code is the following:
CREATE TABLE #tempScaffStandingByTime
(
TotalStanding INT,
MonthsAgo INTEGER
)
DECLARE #StartDate DATETIME = null
DECLARE #months INTEGER = 12
use [Safetrak-BradyTechUK]
WHILE #months >= 0
BEGIN
SET #StartDate = DATEADD(mm, -12 + #months, DATEADD(mm, 0, DATEADD(mm,
DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, #months
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > #StartDate)
group by a.uid
SET #months -= 3
END
SELECT * FROM #tempScaffStandingByTime
DROP TABLE #tempScaffStandingByTime
This results in the input which I want:
I then tried to import this code into my stored procedure
DECLARE #Query varchar (8000)
, #Account varchar (100) = 'BradyTechUK'
SET #Account = 'USE [Safetrak-' + #Account + ']'
/************************************************************************************/
/********** Create Table to hold data ***********************************************/
CREATE TABLE #tempScaffStandingByTime
(
TotalStanding INT,
MonthsAgo INTEGER
)
/************************************************************************************/
/********** Populate temp table with data *******************************************/
DECLARE #StartDate DATETIME = null
DECLARE #months INTEGER = 12
SET #Query= +#Account+ '
WHILE '+#months+' >= 0
BEGIN
SET '+#StartDate+' = DATEADD(mm, -12 + ('+#months+', DATEADD(mm, 0, DATEADD(mm, DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, '+#months+'
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > '+#StartDate+')
group by a.uid
SET '+#months+' -= 3
END'
EXEC (#Query)
/************************************************************************************/
/********** Select Statement to return data to sp ***********************************/
Select TotalStanding
, MonthsAgo
FROM #tempScaffStandingByTime
/************************************************************************************/
DROP TABLE #tempScaffStandingByTime
But when loading the stored procedure in SSRS I get a conversion error.
I can convert my parameter to a string, but then it won't count anymore.
I searched far and wide on the internet, tried various things, but can't get it to work.
Any help is appreciated, thanks!
It looks like your problem original comes from the lack of conversion between the INT in #months and your VARCHAR in #Accounts and #Query.
You need to cast the months to a string to append it, otherwise the SQL Server thinks you're trying to do addition.
However you'll also have problems with the usage of your #StartDate variable as you try to set it via your dynamic SQL which is not going to work like that - and as with #months it'll have an incorrect datatype, but I'm also unsure why it's written as is, and what you're tying to achieve with it
I think - from what you're writing - that this might be what you're looking for?
SET #Query= #Account + '
DECLARE #StartDate DATETIME = null
DECLARE #months VARCHAR(2) = ''12''
WHILE #months >= 0
BEGIN
SET #StartDate = DATEADD(mm, -12 + #months, DATEADD(mm, 0, DATEADD(mm, DATEDIFF(mm,0,GETDATE()-1), 1)))
INSERT INTO #tempScaffStandingByTime
select TOP 1 COUNT(*) OVER () AS TotalRecords, #months, #StartDate
from asset a
join wshhistory h on h.assetid = a.uid
where a.deleted = 0 and h.assetstate <> 6
AND (dbo.getdecommissiondate(a.uid) > #StartDate)
group by a.uid
SET #months -= 3
END'
EXEC (#Query)
We have a website in ASP.NET MVC 5 with Entity Framework.
When a logged in user made changes in UI (i.e. update the data) we save/update/delete the data in SQL Server as per operation performed by the user.
We also have a trigger for audit trailing.
With the trigger, table format for storing data is as below:
[AuditID]
[Type] -- Contains operation performed (Insert (I), Update (U), Delete (D))
[TableName]
[PK] -- Primary Key
[FieldName]
[OldValue]
[NewValue]
[UpdateDate]
[UserName]
We are storing SYSTEM_USER in [UserName] column.
If we have any solution to store the [UserName] who actually made changes from UI instead of system_user?
Do we have any approach to pass [UserName] from application (UI) to the trigger?
Please share your thoughts.
I have one solution - to add UpdatedBy column name in all the tables so that trigger can easily get the value of UpdatedBy column from magic tables or from main tables.
Please suggest best approach.
Below is the trigger used.
CREATE TRIGGER [ids].[tr_AuditEmploee]
ON Employee
FOR INSERT, UPDATE, DELETE
AS
DECLARE #bit INT,
#field INT,
#maxfield INT,
#char INT,
#fieldname VARCHAR(128),
#TableName VARCHAR(128),
#PKCols VARCHAR(1000),
#sql VARCHAR(2000),
#UpdateDate VARCHAR(21),
#UserName VARCHAR(128),
#Type CHAR(1),
#PKSelect VARCHAR(1000)
--You will need to change #TableName to match the table to be audited
SELECT #TableName = 'Employee'
-- date and user
SELECT
#UserName = SYSTEM_USER,
#UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112) + ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT #Type = 'U'
ELSE
SELECT #Type = 'I'
ELSE
SELECT #Type = 'D'
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT
#PKCols = COALESCE(#PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE
pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT
#PKSelect = COALESCE(#PKSelect+'+','')
+ '''' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +', d.' + COLUMN_NAME + '))+'''''
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE
pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF #PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, #TableName)
RETURN
END
SELECT
#field = 0,
#maxfield = MAX(ORDINAL_POSITION)
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
WHILE #field < #maxfield
BEGIN
SELECT #field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND ORDINAL_POSITION > #field
SELECT #bit = (#field - 1 )% 8 + 1
SELECT #bit = POWER(2,#bit - 1)
SELECT #char = ((#field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),#char, 1) & #bit > 0 OR #Type IN ('I','D')
BEGIN
SELECT #fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND ORDINAL_POSITION = #field
SELECT #sql = '
insert [audit].[AuditEmployee] ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select ''' + #Type + ''','''
+ #TableName + ''',' + #PKSelect
+ ',''' + #fieldname + ''''
+ ',convert(varchar(1000),d.' + #fieldname + ')'
+ ',convert(varchar(1000),i.' + #fieldname + ')'
+ ',''' + #UpdateDate + ''''
+ ',''' + #UserName + ''''
+ ' from #ins i full outer join #del d'
+ #PKCols
+ ' where i.' + #fieldname + ' <> d.' + #fieldname
+ ' or (i.' + #fieldname + ' is null and d.' + #fieldname + ' is not null)'
+ ' or (i.' + #fieldname + ' is not null and d.' + #fieldname + ' is null)'
EXEC (#sql)
END
END
declare #ProductDetails as table(ProductName nvarchar(200),ProductDescription nvarchar(200),
Brand nvarchar(200),
Categry nvarchar(200),
Grop nvarchar(200),
MRP decimal,SalesRate decimal,CurrentQuantity decimal,AvailableQty decimal)
declare #AvailableQty table(prcode nvarchar(100),Aqty decimal)
declare #CloseStock table(pcode nvarchar(100),
Cqty decimal)
insert into #CloseStock
select PCODE ,
0.0
from producttable
insert into #AvailableQty
select PCODE ,
0.0
from producttable
--Current Qty
--OpenQty
update #CloseStock set Cqty=((OOQTY+QTY+SRRQTY+PYQTY)-(STQTY+PRRQTY))
from
(
select PC.PCODE as PRODUCTCODE,
--Opening
(select case when SUM(PU.Quantity)is null then 0 else SUM(PU.Quantity) end as Q from ProductOpeningYearEnd PU
where PC.PCODE=PU.ProductName) as OOQTY,
--Purchase
(select case when SUM(PU.quantity)is null then 0 else SUM(PU.quantity) end as Q from purchase PU
where PC.PCODE=PU.prdcode ) as QTY,
--Sales
(select case when SUM(ST.QUANTITY)is null then 0 else SUM(ST.QUANTITY)end as Q2 from salestable ST
where PC.PCODE=ST.PRODUCTCODE and ST.status!='cancel' )as STQTY,
--Physical Stock
(select case when SUM(PS.Adjustment)is null then 0 else SUM(PS.Adjustment)end as Q3 from physicalstock PS
where PC.PCODE=PS.PCODE )as PYQTY,
--Sales Return
(select case when SUM(SR.quantity)is null then 0 else SUM(SR.quantity)end as Q3 from salesreturn SR
where PC.PCODE=SR.prdcode )as SRRQTY,
--Purchase Return
(select case when SUM(PR.quantity)is null then 0 else SUM(PR.quantity)end as Q3 from purchasereturn PR
where PC.PCODE=PR.prdcode )as PRRQTY
from producttable PC
group by PC.PCODE
)t
where PCODE=t.PRODUCTCODE
--Available
update #AvailableQty set Aqty=((CCqty-GIQty)+(GOQty))
--((OOQTY+QTY+SRRQTY+PYQTY)-(STQTY+PRRQTY))
from
(
select PC.PCODE as PRODUCTCODE,
--GoodsIn
(select case when SUM(GI.quantity)is null then 0 else SUM(GI.quantity) end as Q from goodsin GI
where PC.PCODE=GI.productcode) as GIQty,
--GoodsOut
(select case when SUM(GUT.quantity)is null then 0 else SUM(GUT.quantity) end as Q from goodsout GUT
where PC.PCODE=GUT.productcode ) as GOQty,
--Current Stock
(select CS.Cqty as Q from #CloseStock CS
where PC.PCODE=CS.pcode ) as CCqty
from producttable PC
group by PC.PCODE
)t
where prcode=t.PRODUCTCODE
insert into #ProductDetails
select PCODE,[DESCRIPTION],BRAND,CATEGORY,DEPARTMENT,MRP,SALERATE,0,0
from producttable
update #ProductDetails set CurrentQuantity=pcqty,AvailableQty=acqty
from
(
select pt.ProductName as pn,cs.Cqty as pcqty,ac.Aqty as acqty from #ProductDetails pt
inner join #CloseStock cs on pt.ProductName=cs.pcode
inner join #AvailableQty ac on pt.ProductName=ac.prcode
)t
where ProductName=t.pn
select * from #ProductDetails
end
This not working when productable in pcode field add ant (-.&) this kind of symbol i want to even allow in pcode field,
please help me how i can allow any symbol in query
(problem with this code)
update #AvailableQty set Aqty=((CCqty-GIQty)+(GOQty))
from
(
select PC.PCODE as PRODUCTCODE,
--GoodsIn
(select case when SUM(GI.quantity)is null then 0 else SUM(GI.quantity) end as Q from goodsin GI
where PC.PCODE=GI.productcode) as GIQty,
--GoodsOut
(select case when SUM(GUT.quantity)is null then 0 else SUM(GUT.quantity) end as Q from goodsout GUT
where PC.PCODE=GUT.productcode ) as GOQty,
--Current Stock
(select CS.Cqty as Q from #CloseStock CS
where PC.PCODE=CS.pcode ) as CCqty
from producttable PC
group by PC.PCODE
)t
where prcode=t.PRODUCTCODE
The problem here isn't with the symbols you're using, it's that you are assigning the value of a subquery to a single column in the result set. For example:
(select case when SUM(PR.quantity)is null then 0 else SUM(PR.quantity)end as Q3 from purchasereturn PR
where PC.PCODE=PR.prdcode )as PRRQTY
Note that this is allowed only if the subquery returns only a single value; otherwise, we don't know which of the values should be assigned to the column.
If you expect your subqueries to return multiple values and you just want an arbitrary one, use TOP 1 in the subquery to only return 1 value. Otherwise, you'll have to debug each subquery to figure out which returns multiple results and is causing the issue.
I'm having trouble with this stored procedure, could you please help.
This is error I'm getting - running all this via Oracle Sql developer on SQL Server 2000 hosted elsewhere.
Error
Error starting at line 1 in command:
execute dbo.OF_ASEQ_EH_BROWNBIN 'dbo.EH_Brownbin_Josh','Match', 1
Error report:
Incorrect syntax near the keyword 'BEGIN'.
Procedure
ALTER PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN]
#JvarTable Varchar(250),
#varColumn Varchar(250),
#optInterval int
AS
declare #Sql_string nvarchar(4000)
declare #myERROR int
declare #myRowCount int
declare #topseed int
declare #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
declare #RowCnt int
declare #MaxRows int
declare #col_Name nvarchar(250)
declare #col_UPRN nvarchar(250)
declare #col_JoinedOn smalldatetime
begin
set #Sql_string = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
set #stg_topseed = #Sql_string
set #topseed = convert(int, #stg_topseed)
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
select #RowCnt = 1
declare #Import table
(
rownum int IDENTITY (1, 1) Primary key NOT NULL ,
col_Name nvarchar(250),
col_UPRN nvarchar(250),
col_JoinedOn smalldatetime
)
set #sql_string = 'insert into #Import (col_Name, col_UPRN, col_JoinedOn) select Name, UPRN, JoinedOn from ' + #JvarTable + ' where ' + #varColumn +' is null'
exec #Sql_string
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
select #MaxRows=count(*) from #Import
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
-- Next new seed
select #topseed = #topseed + #optInterval
<br/>
while #RowCnt <= #MaxRows
begin
select #col_Name = col_Name from #Import where rownum = #RowCnt
select #col_UPRN = col_UPRN from #Import where rownum = #RowCnt
select #col_JoinedOn = col_JoinedOn from #Import where rownum = #RowCnt
set #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = cast((' + #topseed + ') as char) where Name = ''' + #col_Name + ''' and UPRN = ''' + #col_UPRN + ''' and JoinedOn = ''' + #col_JoinedOn + ''' '
exec (#Sql_string)
select #topseed = #topseed + #optInterval
Select #RowCnt = #RowCnt + 1
end
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
HANDLE_ERROR:
RETURN #myERROR
end
Whereas in Oracle, you need to have DECLARE - BEGIN - END, in MSSQL you do not have to use the BEGIN/END keywords on the procedure body.
Note that the label HANDLE_ERROR: is outside the BEGIN/END.
My guess is that removing the BEGIN (after the DECLARE block) and the END (before SELECT #myERROR=...), the error goes away.
Edit:
I guess I don't get the following statement:
set #Sql_string = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
set #stg_topseed = #Sql_string
set #topseed = convert(int, #stg_topseed)
You assign a string var, copy the value to another string var, and, instead of executing the SQL statement, you cast the string var into an int. (?)
There were several errors in that code and there's probably a better, set based, way to solve the problem this stored procedure is for. (But that's another question and requires knowledge of the target tables that was not provided.)
The following code should be a step closer to what you're looking for.
Changes:
Edited suspicious code, cast((' + #topseed + ') as char) is that column really char? or is it varchar(something)?
Corrected logic around #topseed fetch.
Corrected logic around Import table use.
Corrected update SQL generation.
Removed extraneous Begin/ENDs.
Removed extraneous HTML (<br/>).
Wrapped procedure with Begin/END.
Added Go at the end.
Code:
ALTER PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN]
#JvarTable Varchar(250),
#varColumn Varchar(250),
#optInterval int
AS
BEGIN
DECLARE #Sql_string nvarchar(4000)
DECLARE #myERROR int
DECLARE #myRowCount int
DECLARE #topseed int
DECLARE #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
DECLARE #RowCnt int
DECLARE #MaxRows int
DECLARE #col_Name nvarchar(250)
DECLARE #col_UPRN nvarchar(250)
DECLARE #col_JoinedOn smalldatetime
SET #Sql_string = 'select top 1 #stg_topseed = ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
EXEC SP_EXECUTESQL #Sql_string, N'#stg_topseed varchar(100) OUTPUT', #stg_topseed OUTPUT
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
SET #topseed = CONVERT(int, #stg_topseed)
/* Can't use a table variable with EXEC and/or SP_EXECUTESQL.
Therefore, forced to use a temporary table.
*/
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id('#Import') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE #Import
CREATE table #Import
(
rownum int IDENTITY (1, 1) Primary key NOT NULL,
col_Name nvarchar(250),
col_UPRN nvarchar(250),
col_JoinedOn smalldatetime
)
SET #sql_string = 'insert into #Import (col_Name, col_UPRN, col_JoinedOn) select Name, UPRN, JoinedOn from ' + #JvarTable + ' where ' + #varColumn +' is null'
EXEC (#Sql_string)
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
SELECT #MaxRows=count(*) from #Import
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
-- Next new seed
SELECT #topseed = #topseed + #optInterval
SELECT #RowCnt = 1
WHILE #RowCnt <= #MaxRows
BEGIN
SELECT #col_Name = col_Name from #Import where rownum = #RowCnt
SELECT #col_UPRN = col_UPRN from #Import where rownum = #RowCnt
SELECT #col_JoinedOn = col_JoinedOn from #Import where rownum = #RowCnt
SET #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = ''' + CAST (#topseed AS varchar(250)) + ''' where Name = ''' + #col_Name + ''' and UPRN = ''' + #col_UPRN + ''' and JoinedOn = ''' + CAST(#col_JoinedOn AS varchar(250)) + ''' '
EXEC (#Sql_string)
SELECT #topseed = #topseed + #optInterval
SELECT #RowCnt = #RowCnt + 1
END
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
HANDLE_ERROR:
RETURN #myERROR
END
GO
I've been doing housekeeping on StackOverflow, and realised I hadn't (or accepted) answered the question I asked a long time ago. I couldn't remember which method/work-around I decided on, but I felt it's important to upload my accepted and working script, although I no longer need it.
Nevertheless, I sincerely hope this code will help the next person who has similar question to mine.
CREATE PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN] #JvarTable nvarchar(250), #varColumn nvarchar(250), #optInterval int AS
/*
Procedure OF_ASEQ_EH_BROWNBIN
Created by Joshua White
When 20100902
Purpose To fill up column with new sequence numbers
Arguments JvarTable - Table name
varColumn - Column name
optInterval - Steps in increment in building new sequence (Should be 1 (one))
Example script to begin procedure
EXECUTE [dbo].[OF_ASEQ_EH_BROWNBIN] 'EH_Brownbin_Josh', 'Match', 1
PLEASE NOTE - Typically Stored Procedures are supposed to be flexible to work on
any tables, but due to complications with SQL Server 2000 and problems with
Cursors, we have to use manual scripts and this Stored Procedure will only work
on EH_BrownBin table ONLY.
Any questions about this, please send email to
<email deleted>
*/
declare #Sql_string nvarchar(4000)
declare #myERROR int
declare #myRowCount int
/* Fetching the last number in rows of table in question */
declare #topseed int
declare #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
declare #RowCnt int
declare #MaxRows int
declare #rc int
declare #colu_Name nvarchar(250)
declare #colu_UPRN nvarchar(250)
declare #colu_JoinedOn smalldatetime
Begin
set #stg_topseed = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
exec (#stg_topseed)
/* Begin collecting all rows with nulls in specified column */
select #RowCnt = 1
declare #Import table
(
rownum int IDENTITY (1, 1) Primary key NOT NULL ,
colu_Name nvarchar(250),
colu_UPRN nvarchar(250),
colu_JoinedOn smalldatetime
)
set nocount on
select #MaxRows = count(*) from #Import
-- Next new seed
select #stg_topseed = #stg_topseed + #optInterval
select #rc=0
while #RowCnt <= #MaxRows
begin
select #colu_Name = colu_Name from #Import where rownum = #RowCnt
select #colu_UPRN = colu_UPRN from #Import where rownum = #RowCnt
select #colu_JoinedOn = colu_JoinedOn from #Import where rownum = #RowCnt
set #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = ' + #stg_topseed + ' where Name = ''' + #colu_Name + ''' and UPRN = ''' + #colu_UPRN + ''' '
exec (#Sql_string)
select #stg_topseed = #stg_topseed + #optInterval
Select #RowCnt = #RowCnt + 1
end
print 'END'
end