How to select columns whose names are in a column from another table? - select

In a PROC SQL how to do this?
PROC SQL;
CREATE TABLE SASUSER.COLS (
COL VARCHAR(20)
);
INSERT INTO SASUSER.COLS
VALUES('NUM_ENQ_ANO')
VALUES('NUM_ENQ_IDT')
VALUES('BEN_RNG_GEM')
VALUES('NUM_ENQ_IDT')
VALUES('BEN_SEX_COD')
VALUES('BEN_NAI_ANN')
VALUES('BEN_NAI_MOI');
CREATE TABLE SASUSER.TEST AS
SELECT (SELECT * FROM SASUSER.COLS)
FROM LIBERICO.IR_BEN_R_202107;
QUIT;
The error message is this one:
ERROR: Subquery evaluated to more than one row.

I am presuming by your tables name that you are interested in retrieving the columns that are in COLS from IR_BEN_R_202107. If that is the case a simple macro-variable should do the trick:
proc sql noprint;
select col into :cols separated by ", "
from cols
;
create table test as
select &cols.
from liberico.ir_ben_r_202107
;
quit;

Related

Postgresql : ERROR: in creating temp table with list object values

I am writing a Postgresql function (using pgAdmin GUI) that will be invoked from my Spring Boot application with java list object as parameters
My actual requirement is mentioned here and with the suggestions to create a temp table with list values to optimize query, following is the Postgres function which I have tried by referring from here:
CREATE FUNCTION public."getInventory"("vals1Arg" character varying[], "vals2Arg" character varying[])
RETURNS "INVENTORY"
LANGUAGE 'sql'
AS
$BODY$
// I assume the below two lines create two temp tables and populate the table
with my list object values
CREATE TEMP TABLE t1 AS
SELECT * FROM VALUES(vals1Arg)
CREATE TEMP TABLE t2 AS
SELECT * FROM VALUES(vals2Arg)
SELECT * FROM "INVENTORY"
where "COLUMN_1" in (select * from t1)
and "COLUMN_2" in (Select * from t2);
$BODY$;
Following is the code snippet by how I am invoking postgres function
#Query(nativeQuery = true, value = "select \"getInventory\" (:vals1Arg,:vals2Arg)")
List<Inventory> getInventoryInfo(List<String> vals1Arg, List<String> vals2Arg);
As the list is going to be huge, I am creating a temporary table with values from the list object paramaters and use it in my select query
Thank you in advance !!
There are several problems:
The syntax of the CREATE TABLE ... AS should be
CREATE TABLE ... AS
SELECT * FROM (VALUES (...)) AS alias;
instead of
CREATE TABLE ... AS
SELECT * FROM VALUES (...);
You need these parentheses and the alias.
The subselect in the query won't work, as it compares a varchar (COLUMN_1) with a varchar[] (the column of the temporary table).
To make that work, you'd have to
SELECT * FROM "INVENTORY"
WHERE "COLUMN_1" = ANY (SELECT * FROM t1);
If you want to create temporary tables rather than using the array directly in the SELECT, you had better
CREATE TEMP TABLE t1 AS
SELECT * FROM unnest(vals1Arg) AS u(c);
CREATE TEMP TABLE t2 AS
SELECT * FROM unnest(scomoIdList) AS u(c);
ANALYZE t1, t2;
RETURN QUERY SELECT * FROM "INVENTORY"
JOIN t1 ON "INVENTORY"."COLUMN_1" = t1.c
JOIN t2 ON "INVENTORY"."COLUMN_2" = t2.c;
This assumes that the lists don't contain duplicate entries.

Atomic compound statement works different in Db2

When issuing the following statement, it prints the modified rows with Atomic, but not without it. However, I haven't found something in the documentation that explains this behavior.
--#SET TERMINATOR #
drop table mytable#
CREATE TABLE mytable (
col1 INTEGER
) #
SELECT * FROM new TABLE (INSERT INTO mytable (col1) VALUES (1)) #
SELECT * FROM mytable #
BEGIN ATOMIC
SELECT col1 FROM new TABLE (INSERT INTO mytable (col1) VALUES (2));
END #
SELECT * FROM mytable #
BEGIN
SELECT col1 FROM new TABLE (INSERT INTO mytable (col1) VALUES (3));
END #
I got this output:

Invalid column name of temp table

I want to create a procedure in which I insert data into several tables. I need to get the inserted ID's so I create temp table in which I catch them. The problem is that I receive an error "Invalid column name 'app_guid'" and "Invalid column name 'app_nazwa_pliku'" but I create temp tables with such columns. Do you happen to know what's wrong with my code?
create procedure p_paseczek_przenies
as
declare #new_nr_sprawy varchar(50)
if object_id('tempdb..##paseczki') is not null drop table ##paseczki
select
top 1 with ties
s.sp_numer as SprawaGlowna_sp_numer,
s.sp_id as SprawaGlowna_sp_id
,Paseczek.max_ak_id as Paseczek_max_ak_id
,apisp_data_przyjscia
,app_guid
,app_nazwa_pliku
into ##paseczki
from sprawa as s
join akcja as a on a.ak_sp_id=s.sp_id and ak_akt_id=111
join sprawa_powiazania as sp on s.sp_id=sp.sp_id and rodzaj_powiazania='SPRAWY POLUBOWNE'
join (select max(ak_id) max_ak_id,ak_sp_id from akcja
where ak_akt_id=1089
group by ak_sp_id) as Paseczek on Paseczek.ak_sp_id=sp.sp_id_powiazana
join akcja_pismo on apis_ak_id=max_ak_id
join akcja_pismo_przychodzace on apis_apisp_id=apisp_id
join akcja_pismo_plik on app_apis_id=apis_id
where s.sp_numer=#new_nr_sprawy
order by ROW_NUMBER() over (partition by s.sp_id order by paseczek.max_ak_id desc)
if exists (select * from ##paseczki)
begin
if object_id('tempdb..##akcja') is not null drop table ##akcja
create table ##akcja (
ak_id int
,apisp_data_przyjscia datetime
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja as target using (
select * from ##paseczki) as source on 1=0
when not matched then insert
(ak_akt_id, ak_sp_id, ak_kolejnosc, ak_interwal, ak_zakonczono, ak_pr_id, ak_publiczna)
values (1089,SprawaGlowna_sp_id,1,1,getdate(),5,1)
output inserted.ak_id,source.apisp_data_przyjscia,source.app_guid,source.app_nazwa_pliku
into ##akcja;
insert into rezultat
(re_ak_id, re_ret_id, re_data_planowana, re_us_id_planujacy, re_data_wykonania, re_us_id_wykonujacy, re_konczy)
select ak_id,309,getdate(),5,getdate(),5,1 from ##akcja
if object_id('tempdb..##akcja_pismo_przychodzace') is not null drop table ##akcja_pismo_przychodzace
create table ##akcja_pismo_przychodzace (
apisp_id int
,ak_id int
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja_pismo_przychodzace as target using (
select * from ##akcja) as source on 1=0
when not matched then insert
(apisp_data_przyjscia)
values (apisp_data_przyjscia)
output inserted.apisp_id,source.ak_id,source.app_guid,source.app_nazwa_pliku
into ##akcja_pismo_przychodzace;
if object_id('tempdb..##akcja_pismo') is not null drop table ##akcja_pismo
create table ##akcja_pismo (
apis_id int
,app_guid varchar(max)
,app_nazwa_pliku varchar(max)
)
merge akcja_pismo as target using (
select * from ##akcja_pismo_przychodzace) as source on 1=0
when not matched then insert
(apis_ak_id, apis_apisp_id, apis_data_stworzenia,[apis_us_id_tworzacy])
values (ak_id,apisp_id,getdate(),5)
output inserted.apis_id,source.app_guid,source.app_nazwa_pliku
into ##akcja_pismo;
alter table [dm_data_bps].[dbo].[akcja_pismo_plik] disable trigger [tr_akcja_pismo_plik_ins]
insert into akcja_pismo_plik
([app_guid],[app_apis_id],[app_nazwa_pliku])
select [app_guid],[apis_id],[app_nazwa_pliku] from ##akcja_pismo
alter table [dm_data_bps].[dbo].[akcja_pismo_plik] enable trigger [tr_akcja_pismo_plik_ins]
end
SQL Server compiles the procedure at creation and when it is first executed, verifying the entire procedure based on the context at that time.
For example, try the following query:
CREATE PROCEDURE P
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
SELECT 1 Y INTO #T
SELECT Y FROM #T
GO
CREATE TABLE #T (X INT)
GO
EXEC P
You will get an error ("Invalid column name 'Y'."), because when the procedure is compiled the table #T has only the column X.
To avoid this problem, you should make sure that the table #T either does not exist or has the right columns, before the procedure is executed.
One way would be to have another stored procedure (a wrapper):
CREATE PROCEDURE P1
AS
SELECT 1 Y INTO #T
SELECT Y FROM #T
GO
CREATE PROCEDURE P2
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
EXEC P1
GO
CREATE TABLE #T (X INT)
GO
EXEC P2
GO
DROP PROCEDURE P1, P2
--DROP TABLE #T
Another way would be to use dynamic SQL, because that code is compiled separately, as if it would be another stored procedure.
A better way would be to make sure that temp tables are uniquely named in each stored procedure, unless sharing data between them is desired. For the later case, you can read http://www.sommarskog.se/share_data.html#temptables for more insights.
This error is also encountered when a stored procedure creates a #temp table and then fires a trigger which creates a #temp table with the same name. The SP #temp table is referenced by the trigger when the column names are explicit, (like SELECT id FROM #temp;), but the local trigger #temp table is referenced when SELECT * FROM #temp; is used.
Microsoft, if you are listening, could you kindly attend to it and retrofit existing supported versions with a maintenance update?

Pass String in Postgres Query

I am using Postgresql 9.3 and what I am trying to do is Passing column names as string into my query. For newtable my column number can be dynamic sometimes it might be 3 or more for which I am trying to select column from another table and pssing relut of my query as string in the existing query
Please help how can i do this
select * from crosstab (
'select "TIMESTAMP_S","VARIABLE","VALUE" from archieve_export_db_a3 group by 1,2,3 order by 1,2',
'select distinct "VARIABLE" From archieve_export_db_variables order by 1'
) AS newtable (TIMESTAMP_S int,_col1 integer,_col2 integer);

T-SQL Loop in a stored proc

how do I loop through a comma separated variable using tsql in a stored proc
So for instance my list would look like this
"1,2,3,4,5,6,7,8,9,10"
and I would loop thought this list and made some necessary table
insert based on this list
You could do it a couple ways, but if this would be a list of ID's it could be done like this as well. It would change your list format a bit.
UPDATE table
SET column = value
WHERE ID in ('1','2','3','4','5','6','7','8','9','10')
You could do a loop as well
DECLARE #List CHAR(100)
DECLARE #ListItem int
DECLARE #Pos int
SET #List = '1,2,3,4,5,6,7,8,9,10'
WHILE LEN(#List) > 0
BEGIN
--Pull Item Frim List
SET #Pos = CHARINDEX(',', #List)
IF #Pos = 0
BEGIN
SET #ListItem = #List
END
ELSE
BEGIN
SET #ListItem = SUBSTRING(#List, 1, #Pos - 1)
END
UPDATE table
SET column = value
WHERE ID = #ListItem
--Remove Item Frim List
IF #Pos = 0
BEGIN
SET #List = ''
END
ELSE
BEGIN
SET #List = SUBSTRING(#List, #Pos + 1, LEN(#List) - #Pos)
END
END
I'd try to avoid looping and insert the rows directly from your comma list.
Use a table values parameter (new in SQl Server 2008). Set it up by creating the actual table parameter type:
CREATE TYPE IntTableType AS TABLE (ID INTEGER PRIMARY KEY)
Your procedure would then be:
Create Procedure up_TEST
#Ids IntTableType READONLY
AS
SELECT *
FROM ATable a
WHERE a.Id IN (SELECT ID FROM #Ids)
RETURN 0
GO
if you can't use table value parameters, see: "Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog, then there are many ways to split string in SQL Server. This article covers the PROs and CONs of just about every method. in general, you need to create a split function. This is how a split function can be used to insert rows:
INSERT INTO YourTableA (colA)
SELECT
b.col1
FROM dbo.yourSplitFunction(#Parameter) b
I prefer the number table approach to split a string in TSQL but there are numerous ways to split strings in SQL Server, see the previous link, which explains the PROs and CONs of each.
For the Numbers Table method to work, you need to do this one time table setup, which will create a table Numbers that contains rows from 1 to 10,000:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this split function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
Create Procedure up_TEST
#Ids VARCHAR(MAX)
AS
SELECT * FROM ATable a
WHERE a.Id IN (SELECT ListValue FROM dbo.FN_ListToTable(',',#Ids))
GO
or insert rows from it:
Create Procedure up_TEST
#Ids VARCHAR(MAX)
,#OtherValue varchar(5)
AS
INSERT INTO YourTableA
(colA, colB, colC)
SELECT
ListValue, #OtherValue, GETDATE()
FROM dbo.FN_ListToTable(',',#Ids)
GO
Using CTE (Common Table Expression) is the most elegant solution I think check this question on stackoverflow,
T-SQL: Opposite to string concatenation - how to split string into multiple records