I need to run a SELECT statement where the column names are variable, as follows:
query.SQL.Text := 'SELECT A.:COLUMN '+
' FROM A ';
query.ParamByName('COLUMN').AsString := 'column_name';
query.Open();
But when I do this, there's an error in the SQL syntax because the component runs as:
SELECT A.'column_name'
FROM A
Is there a way to set these parameters without the quotes so I can dynamically choose columns?
You can change your query as follow (create subqueries with all columns). All columns that you select have to be the same type:
select myData
from (
select col1 as myData, 'col1' as colName from A
union all
select col2, 'col2' from A
union all
select colLast, 'colLast' from A
) as mTbl
where colName=:COLUMN
Related
I am trying to call the variable in a select query like below:
BEGIN
DECLARE TGT_LOAD_STATUS_TBL STRING;
SET TGT_LOAD_STATUS_TBL=''||PROJ_ID||'.'||TGT_SCHEMA||'.'||LOAD_STATUS_TBL||'';
FOR FETCH_TEST IN (select col1 from TGT_LOAD_STATUS_TBL WHERE LOAD_STATUS='N')
DO
INSERT INTO project.datasetid.table VALUES(FETCH_TEST.col1);
END FOR;
END
Is there any way to append the variable in a select query?
You can use build your SQL statement by concatenating some strings together and then execute it using EXECUTE IMMEDIATE. This is exactly the use case that EXECUTE IMMEDIATE exists for
I don't think it's a good practice to update a table one by one within a loop.
Instead consider a bulk update using a dynamic sql like below
EXECUTE IMMEDIATE FORMAT("""
INSERT INTO table1
SELECT col1 FROM `%s` WHERE LOAD_STATUS='N'
""", TGT_LOAD_STATUS_TBL);
Test Query:
DECLARE TGT_LOAD_STATUS_TBL DEFAULT 'table2';
CREATE TEMP TABLE table1 (col1 STRING);
CREATE TEMP TABLE table2 AS
SELECT 'a' col1, 'N' LOAD_STATUS UNION ALL
SELECT 'b', 'Y' UNION ALL
SELECT 'c', 'N' UNION ALL
SELECT 'd', 'N' UNION ALL
SELECT 'e', 'N' ;
EXECUTE IMMEDIATE FORMAT("""
INSERT INTO table1
SELECT col1 FROM `%s` WHERE LOAD_STATUS='N'
""", TGT_LOAD_STATUS_TBL);
SELECT * FROM table1;
I need to find out rows that are present in table A and missing from table B (using LEFT JOIN) wherein table A and table B are two tables with same structure but within different schema.
But the query has to be constructed using Dynamic SQL and the columns that need to be used for performing JOIN are stored in a string. How to extract the column names from string and use them to dynamically construct below query :
Database is Azure SQL Server
eg :
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
Query to be constructed based on columns defined in ColNames :-
SELECT *
FROM Table A
Left Join
Table B
ON A.col1 = B.col1
AND A.col2 = B.col2
AND B.col1 IS NULL AND B.col2 IS NULL
If the number of columns in #ColNames is more then the SELECT statement needs to cater for all the column.
Without knowing the full context, try this:
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
DECLARE #JoinContion NVARCHAR(MAX) = ''
DECLARE #WhereCondition NVARCHAR(MAX) = ''
SELECT #JoinContion += CONCAT('[a].', QUOTENAME(Value), ' = ', '[b].', QUOTENAME(Value), (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
,#WhereCondition += CONCAT('[a].', QUOTENAME(Value), ' IS NULL', (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
FROM STRING_SPLIT(#ColNames,N',')
SELECT #JoinContion, #WhereCondition
String_Split: To split the input string into columns
Lead: to determine if we need the AND keyword when it's not the last row.
Be aware the NOT EXISTS is probably a better solution then LEFT JOIN
I want to create RDLC report ,but the problem is that Columns in a table returned by the stored procedure are Dynamic, means Columns can be increased or decrease depends on the condition.
I have Created procedure.
alter proc sp_GetEmpBranAndDesigWise(
#BranchId nvarchar(200),
#ZoneId nvarchar(200)
)
as
if 1=0 Begin
set FMTONLY OFF End
select b.BranchName,b.BranchCity,z.ZoneName,b.BranchID,d.DesigName
,Count(d.DesigName) as TotalCount
INTO #RepTablTemp
from Emp_File emp
INNER join Branch b on emp.BranchID=b.BranchID
left join ZoneFile z on z.ZoneID=b.ZoneID
INNER join SWHouse_Production.dbo.emp_DesigFile d on emp.DesigID=d.DesigID
where Convert(nvarchar(250), b.BranchID) like #BranchId
and Convert(nvarchar(250), b.ZoneID) like #ZoneId
group by b.BranchName,z.ZoneName,b.BranchCity,b.BranchID,d.DesigName
order by b.BranchName,z.ZoneName,d.DesigName
--select * from #RepTablTemp order by BranchName,DesigName
--select * from Emp_File where BranchID=1055
Begin
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(DesigName)
from #RepTablTemp
group by DesigName
--order by 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #cols
set #query = N'SELECT BranchName,ZoneName,BranchCity,' + ISNULL(#cols,'0') + N' from
(
select BranchName,ZoneName,BranchCity,TotalCount, DesigName
from #RepTablTemp
) x
pivot
(
max(TotalCount)
for DesigName in (' + #cols + N')
) p '
exec sp_executesql #query;
select 0 AS mycol1int
print #query
drop table #RepTablTemp
End
BranchName|ZoneName|BranchCity|Designation1|Designation2|Designation3
here Designations are dynamic and can be increased,i want this kind of result in RDLC
enter image description here
In attached file highlighted fields are Designations coming from Designation Table.
You can't do that. RDLC expects a fixed "object" for a table. You can pass a dynamic object, but this object must be match with the dataset provided to the table.
But you can use several tablix and show them or not (visibility condition) for an specific condition loaded by a parameter (for example, a kind of table do you want to see or hide).
I am trying to copy over one row from my archive table to my original table.
Without my WHERE clause, the whole table of table2 gets copied to table1.
I don't want this of course. So based on the gridview's ID value listed, the table will copy over only the row whose ID is the same.
When I debug the lines I get the correct ID listed for DisplaySup.Rows(0).Cells(2).Text.
(
val_ID table2.V_ID%type
)
is
begin
execute immediate 'insert into table1 (select * from table2 where V_ID = val_ID)';
end;
Yet I get the error
ORA-00904: "VAL_ID": invalid identifier
Table2 and Table1 have identical columns; so they both have column titled V_ID. I am unsure why Val_ID is flagging an error.
VB.net line of coding:
SupArchive.Parameters.Add("val_ID", OleDbType.VarChar).Value = DisplaySup.Rows(0).Cells(2).Text
So I tried to reference: EXECUTE IMMEDIATE with USING clause giving errors
Like so to fix WHERE:
(
val_ID table2.V_ID%type
)
is
begin
execute immediate 'insert into table1 (select * from table2 where V_ID = '||val_ID||')';
end;
but I get error:
ORA-00904: "val_ID": invalid identifier
Any suggestions on how to fix my stored procedure?
UPDATE:
Tried to do the suggested:
(
val_ID table2.V_ID%type
)
AS
BEGIN
execute immediate 'insert into table1 (col1, col2, col3...)(select col1, col2, col3... from table2 where V_ID = :val_ID)' using val_ID;
end;
but get error:
ORA-00904: "col72": invalid identifier
for col72 after Select statement
EXAMPLE OF MY TABLES (both are identical) purpose of table2 is when a row is deleted in table1, table2 can re-create the user that was deleted
Table1
ID CompanyName FirstName LastName ....(72 cols)
Table2
ID CompanyName FirstName LastName... (72 cols)
You would do best to use a bind variable in your insert statement. Also, you need to list the columns you're inserting into as well as those you're inserting, to avoid the "too many values" error.
Eg:
declare
val_ID table2.V_ID%type := 1;
begin
execute immediate 'insert into table1 (col1, col2, ...) (select col1, col2, ... from table2 where V_ID = :val_ID)' using val_id;
end;
/
Although in this instance there is absolutely no need to use dynamic sql at all, so you could just do:
declare
val_id table2.v_id%type := 1;
begin
insert into table1 (col1, col2, ...)
select col1, col2, ...
from table2
where v_id = val_id;
end;
/
Don't forget to commit after you've run the procedure!
I wrote a stored procedure with a table name as parameter, that checks if there are duplicate rows in this table. The statements are built dynamically of course:
INSERT INTO tmpTable
SELECT col1, col2,... FROM table GROUP BY col1, col2, ... HAVING COUNT(*) > 1;
DELETE FROM tablename FROM tablenname
INNER JOIN tmpTable ON ISNULL(tablename.col1, 0) = ISNULL(tmpTable.col1, 0)
AND ISNULL(tablename.col2, 0) = ISNULL(tmpTable.col2, 0)
AND ...;
INSERT INTO tablename SELECT * FROM tmpTable;
Should work so far, but problem is, that it fails when the table has blob columns, like text. Those can not be compared in the JOIN. I also tried
DELETE FROM tablename GROUP BY col1, col2, ... HAVING COUNT(*) > 1;
but GROUP BY is not supported in DELETE statement directly without self-joining.
Also it's not possible to query information_schema for primary key of this table, since none of these tables has one.
Any ideas? Thanks.
Since the statement is already built dynamically, add casting the relevant columns to varchar(max) for the purpose of join. It's not difficult to figure which columns that are:
select c.name, quotename(c.name, '[')
from
sys.columns c
inner join sys.types t on c.system_type_id = t.system_type_id
where
c.object_id = object_id(#TABLE_NAME)
and c.is_computed = 0
and t.name in ('text', 'image', 'timestamp', 'xml')