I'm trying to write a procedure that concatenates all rows in a table in the case in which the row number is unknown.
I have this code but it is not working.
CREATE PROCEDURE Test (OUT r VARCHAR(3000))
BEGIN
DECLARE RowCnt INT;
DECLARE CurrRow INT ;
SET CurrRow = 1,
r = 'SELECT ',
RowCnt = (SELECT COUNT(*)
FROM tableWithSQLStmnts
)
WHILE CurrRow <= RowCnt DO
BEGIN
SET r = r +
CASE WHEN CurrRow = 1
THEN 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + '
THEN SqlStmnt
ELSE SPACE(0) END ) + ' + CHAR(13)
WHEN i = RowCnt
THEN 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + '
THEN '' '' + SqlStmnt
ELSE SPACE(0) END ) ' + CHAR(13)
ELSE 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + '
THEN '' '' + SqlStmnt
ELSE SPACE(0) END ) + ' + CHAR(13)
END
SET CurrRow = CurrRow + 1 ;
END ;
SET r = r + '
FROM ( SELECT SqlStmnt,
ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
FROM tableWithSQLStmnts t ) D ( SqlStmnt, Seq )
GROUP BY TabName;'
END WHILE;
END
;
I'm getting the following errors:
Syntax error, expected something like ';' between an integer and ','.'.
Unexpected text 'SET'.
New code, as suggested by dnoeth.
REPLACE PROCEDURE Test3 (IN TbName VARCHAR(256)) --, OUT r2 VARCHAR(3000))
BEGIN
DECLARE RowCnt INT;
DECLARE i INT;
DECLARE CurrRow INT;
DECLARE r VARCHAR(3000);
DECLARE r2 VARCHAR(3000);
SET CurrRow = 1;
SET r = 'SELECT ';
SET RowCnt = (SELECT COUNT(*)
FROM tableWithSQLStmnts
WHERE tabname = :TbName
);
WHILE CurrRow <= RowCnt DO
BEGIN
SET r = r ||
'MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || '
THEN '' , '' || SqlStmnt
ELSE '''' END )
'
|| CASE WHEN CurrRow = RowCnt
THEN ''
ELSE ' || '
END;
SET CurrRow = CurrRow + 1 ;
END;
END WHILE;
SET r = r || '
FROM ( SELECT SqlStmnt,
ROW_NUMBER() OVER ( PARTITION BY TbName ORDER BY SQlStmnt )
FROM tableWithSQLStmnts t ) D ( SqlStmnt )
GROUP BY TbName
;';
SET r2 = r;
CALL dbc.sysexecsql(:r);
END;
Now I get this error:
[3706] Syntax error: Column name list shorter than select list.
EDIT 2:
I have now rewritten it like this:
REPLACE PROCEDURE Test3 (IN TabName VARCHAR(256))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE RowCnt INT;
DECLARE Seq INT;
DECLARE QRY VARCHAR(3000);
DECLARE CurrRow INT;
SET QRY= 'INSERT INTO vt21 SELECT ';
SET CurrRow = 1;
CREATE VOLATILE TABLE vt21(QRY VARCHAR(3000)) ON COMMIT PRESERVE ROWS;
SET RowCnt = (SELECT COUNT(*)
FROM TestTable
WHERE tabname = :TabName
);
FOR CurrentRefRow AS SourceCursor CURSOR FOR
SELECT SqlStmnt
FROM TestTable
DO
WHILE CurrRow <= RowCnt
DO
BEGIN
SET QRY = QRY ||
CASE WHEN CurrRow=1
THEN 'MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || '
THEN '' , '' || SqlStmnt
ELSE '''' END ) '
WHEN CurrRow < RowCnt
THEN ', MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || '
THEN '' , '' || SqlStmnt
ELSE '''' END ) '
WHEN CurrRow=RowCnt
THEN ', MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || '
THEN '' , '' || SqlStmnt
ELSE '''' END ) '
ELSE ' || '
END;
SET CurrRow = CurrRow + 1 ;
END;
END WHILE;
SET QRY = QRY || '
FROM ( SELECT SqlStmnt, Tabname,
ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
FROM TestTable t ) D ( Seq, Tabname, SqlStmnt )
GROUP BY TabName
;';
EXECUTE IMMEDIATE QRY;
END FOR;
BEGIN -- return the result set
DECLARE resultset CURSOR WITH RETURN ONLY FOR S1;
SET QRY = 'SELECT * FROM vt21;';
PREPARE S1 FROM QRY;
OPEN resultset;
END;
DROP TABLE vt21;
END;
But I'm getting the following error:
CALL Failed. [3813] The positional assignment list has too many values.
I have tried modifying it but when I delete one value than it says that column name list is longer then the select list.
This is translated to valid syntax for Teradata/Standard SQL (and a bit simplified):
REPLACE PROCEDURE Test (OUT r2 VARCHAR(3000))
BEGIN
DECLARE RowCnt INT;
DECLARE i INT;
DECLARE CurrRow INT;
DECLARE r VARCHAR(3000);
SET CurrRow = 1;
SET r = 'SELECT ';
SET RowCnt = (SELECT Count(*)
FROM tableWithSQLStmnts
);
WHILE CurrRow <= RowCnt DO
BEGIN
SET r = r ||
'MAX( CASE Seq WHEN ' || Cast( CurrRow AS VARCHAR(10) ) || '
THEN '' '' || SqlStmnt
ELSE '''' END )
'
|| CASE WHEN CurrRow = RowCnt
THEN ''
ELSE ' || '
END;
SET CurrRow = CurrRow + 1 ;
END;
END WHILE;
SET r = r || '
FROM ( SELECT department_name--SqlStmnt,
ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
FROM tableWithSQLStmnts t ) D ( SqlStmnt, Seq )
GROUP BY TabName
;';
SET r2 = r;
END
;
What's the content of tableWithSQLStmnts?
Why do you want a single line? There are simpler ways to get a kind of LISTAGG.
Edit:
Based on your comments (here and on Teradata's Developer Exchange) it looks like you want to apply some kind of count to every column. But then you don't need the MAX/CASE/ROW_NUMBER, simply concat all rows for a table and then execute it. This counts NULLs in every column of a table:
REPLACE PROCEDURE Test3 (IN DBName VARCHAR(128),IN TabName VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE QRY VARCHAR(3000);
CREATE VOLATILE TABLE vt21(col VARCHAR(128) CHARACTER SET Unicode, NullCnt BIGINT) ON COMMIT PRESERVE ROWS;
SET QRY = 'INSERT INTO vt21 ';
FOR c AS
SELECT DatabaseName, TableName, ColumnName,
Row_Number()
Over (PARTITION BY tablename
ORDER BY columnname) AS rn,
Count(*)
Over (PARTITION BY tablename) AS Cnt
FROM dbc.ColumnsV
WHERE DatabaseName = :DBName
AND TableName = :TabName
DO
SET QRY = QRY
|| 'SELECT ''' || c.ColumnName
|| ''', COUNT(CASE WHEN ' || c.columnname
|| ' IS NULL THEN 1 END) FROM '
|| c.DatabaseName || '.' || c.TableName
|| CASE WHEN c.rn = c.Cnt -- last row
THEN ';'
ELSE ' UNION ALL '
END;
END FOR;
EXECUTE IMMEDIATE QRY;
BEGIN -- return the result set
DECLARE resultset CURSOR WITH RETURN ONLY FOR S1;
SET QRY = 'SELECT * FROM vt21;';
PREPARE S1 FROM QRY;
OPEN resultset;
END;
DROP TABLE vt21;
END;
CALL Test3('dbc', 'dbcinfoV');
Related
Hello I wrote a function that gets data from 3 tables and input the wanted data into my own created table. After it puts all the data in to the table based on different conditions outputs the wanted data in a string. The problem is the function won't run at all for some reason. I'm thinking it might be a syntax error.
CREATE FUNCTION getRevenue(year1 int, year2 int) returns varchar(50)
BEGIN
declare result varchar(50);
declare messege varchar(50);
declare count1 float;
declare count2 float;
declare num int;
declare num2 int;
declare diff1 int;
declare diff2 int;
declare search varchar(50);
if (year1= '' || year1=null) || (year2='' || year2=null) then
set result="Input year is invalid!";
return result;
else
create table num1 as (SELECT dreamhome.Courses.cid,dreamhome.Courses.credits,
dreamhome.Tuitions.year,dreamhome.Tuitions.fee_per_credit
from ((dreamhome.Students_Courses
inner join dreamhome.Courses on dreamhome.Students_Courses.cid=dreamhome.Courses.cid)
INNER JOIN dreamhome.Tuitions on dreamhome.Students_Courses.year = dreamhome.Tuitions.year));
set num= (SELECT sum(credits) from num1 where year = year1);
set num2 = (SELECT sum(credits) from num1 where year = year2);
set count1 = (select num * fee_per_year from num1 where year = year1);
set count2 = (select num2 * fee_per_year from num1 where year = year2);
if(count1>count2) then
set diff1 = count1-count2;
set result= 'year ' + cast(year1 as char) + ' has revenue: ' + cast(diff1 as char) + ' more then ' + cast(year2 as char) + ' revunue: ' + cast(count2 as char);
select result;
if(count2>count1) then
set diff1 = count2-count1;
set result= 'year ' + cast(year2 as char) + ' has revenue: ' + cast(diff1 as char) + ' more then ' + cast(year1 as char) + ' revunue: ' + cast(count1 as char);
select result;
if(count2=count1)then
set result = 'Year ' + cast(year1 as char) + ' and ' +cast(year2 as char) + ' have the same revenue: ' +cast(count1 as char);
select result;
return result;
END ;
delimiter ;
Don't use () with if, as there is a difference between the if() function versus if statements. If blocks also need a closing end if; Using an if .. elseif .. else block, only 1 end if; needed at the end.
The create table select doesn't need the extra (), the one before the select and at the end should be enough.
No need to select result if the result is set (like it is in the first if), so these have been removed.
if year1= '' || year1=null || year2='' || year2=null then
set result="Input year is invalid!";
return result;
else
create table num1 as (SELECT dreamhome.Courses.cid,dreamhome.Courses.credits,
dreamhome.Tuitions.year,dreamhome.Tuitions.fee_per_credit
from dreamhome.Students_Courses
inner join dreamhome.Courses on dreamhome.Students_Courses.cid=dreamhome.Courses.cid
INNER JOIN dreamhome.Tuitions on dreamhome.Students_Courses.year = dreamhome.Tuitions.year);
set num= (SELECT sum(credits) from num1 where year = year1);
set num2 = (SELECT sum(credits) from num1 where year = year2);
set count1 = (select num * fee_per_year from num1 where year = year1);
set count2 = (select num2 * fee_per_year from num1 where year = year2);
if count1 > count2 then
set diff1 = count1-count2;
set result= 'year ' + cast(year1 as char) + ' has revenue: ' + cast(diff1 as char) + ' more then ' + cast(year2 as char) + ' revunue: ' + cast(count2 as char);
elseif count2 > count1 then
set diff1 = count2-count1;
set result= 'year ' + cast(year2 as char) + ' has revenue: ' + cast(diff1 as char) + ' more then ' + cast(year1 as char) + ' revunue: ' + cast(count1 as char);
else -- counts are the same
set result = 'Year ' + cast(year1 as char) + ' and ' +cast(year2 as char) + ' have the same revenue: ' +cast(count1 as char);
end if;
return result;
end if; -- end the first if/else block.
I wrote this query for searching a string in whole database . Earlier it was working properly now it doesn't fetch full result at all . I don't get what is wrong with this query . Please help
QUERY
/*
- Search through tables to find specific text
- Written by Luis Chiriff (with help from SQL Server Central)
- luis.chiriff#gmail.com # 24/11/2008 # 11:54
*/
-- Variable Declaration
Declare #StringToFind VARCHAR(200), #Schema sysname, #Table sysname, #FullTable int, #NewMinID
int, #NewMaxID int,
#SQLCommand VARCHAR(8000), #BaseSQLCommand varchar(8000), #Where VARCHAR(8000), #CountCheck
varchar(8000) , #FieldTypes varchar(8000),
#cursor VARCHAR(8000), #columnName sysname, #SCn int, #SCm int
Declare #TableList table (Id int identity(1,1) not null, tablename varchar(250))
Declare #SQLCmds table (id int identity(1,1) not null, sqlcmd varchar(8000))
Declare #DataFoundInTables table (id int identity(1,1) not null, sqlcmd varchar(8000))
-- Settings
SET #StringToFind = 'abcdef'
SET NOCOUNT ON
SET #StringToFind = '%'+#StringToFind+'%'
-- Gathering Info
if ((select count(*) from sysobjects where name = 'tempcount') > 0)
drop table tempcount
create table tempcount (rowsfound int)
insert into tempcount select 0
-- This section here is to accomodate the user defined datatypes, if they have
-- a SQL Collation then they are assumed to have text in them.
SET #FieldTypes = ''
select #FieldTypes = #FieldTypes + '''' + rtrim(ltrim(name))+''',' from systypes where collation
is not null or xtype = 36
select #FieldTypes = left(#FieldTypes,(len(#FieldTypes)-1))
insert into #TableList (tablename)
select name from sysobjects
where xtype = 'U' and name not like 'dtproperties'
order by name
-- Start Processing Table List
select #NewMinID = min(id), #NewMaxID = max(id) from #TableList
while(#NewMinID <= #NewMaxID)
Begin
SELECT #Table = tablename, #Schema='dbo', #Where = '' from #TableList where id = #NewMinID
SET #SQLCommand = 'SELECT * FROM ' + #Table + ' WHERE'
-- removed ' + #Schema + '.
SET #cursor = 'DECLARE col_cursor CURSOR FOR SELECT COLUMN_NAME
FROM [' + DB_NAME() + '].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = ''' + #Schema + '''
AND TABLE_NAME = ''' + #Table + '''
AND DATA_TYPE IN ('+#FieldTypes+')'
--Original Check, however the above implements user defined data types --AND DATA_TYPE IN
(''char'',''nchar'',''ntext'',''nvarchar'',''text'',''varchar'')'
EXEC (#cursor)
SET #FullTable = 0
DELETE FROM #SQLCmds
OPEN col_cursor
FETCH NEXT FROM col_cursor INTO #columnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Where = #Where + ' [' + #columnName + '] LIKE ''' + #StringToFind + ''''
SET #Where = #Where + ' OR'
--PRINT #Table + '|'+ cast(len(isnull(#Where,''))+len(isnull(#SQLCommand,'')) as varchar(10))+'|'+#Where
if (len(isnull(#Where,''))+len(isnull(#SQLCommand,'')) > 3600)
Begin
SELECT #Where = substring(#Where,1,len(#Where)-3)
insert into #SQLCmds (sqlcmd) select #Where
SET #Where = ''
End
FETCH NEXT FROM col_cursor INTO #columnName
END
CLOSE col_cursor
DEALLOCATE col_cursor
if (#Where <> '')
Begin
SELECT #Where = substring(#Where,1,len(#Where)-3)
insert into #SQLCmds (sqlcmd)
select #Where --select #Table,count(*) from #SQLCmds
End
SET #BaseSQLCommand = #SQLCommand
select #SCn = min(id), #SCm = max(id) from #SQLCmds
while(#SCn <= #SCm)
Begin
select #Where = sqlcmd from #SQLCmds where ID = #SCn
if (#Where <> '')
Begin
SET #SQLCommand = #BaseSQLCommand + #Where
SELECT #CountCheck = 'update tempcount set rowsfound = (select count(*) '+ substring(#SQLCommand,10,len(#SQLCommand)) + ')'
EXEC (#CountCheck)
if ((select rowsfound from tempcount) > 0)
Begin
PRINT '--- ['+cast(#NewMinID as varchar(15))+'/'+cast(#NewMaxID as varchar(15))+'] '+#Table + ' ----------------------------------[FOUND!]'
--PRINT '--- [FOUND USING:] ' +#SQLCommand
insert into #DataFoundInTables (sqlcmd) select #SQLCommand
EXEC (#SQLCommand)
update tempcount set rowsfound = 0
End
else
Begin
PRINT '--- ['+cast(#NewMinID as varchar(15))+'/'+cast(#NewMaxID as varchar(15))+'] '+#Table
End
End
SET #SCn = #SCn + 1
End
set #NewMinID = #NewMinID + 1
end
if ((select count(*) from sysobjects where name = 'tempcount') > 0)
drop table tempcount
/*
This will now return all the sql commands you need to use
*/
select #NewMinID = min(id), #NewMaxID = max(id) from #DataFoundInTables
if (#NewMaxID > 0)
Begin
PRINT ' '
PRINT ' '
PRINT '-----------------------------------------'
PRINT '----------- TABLES WITH DATA ------------'
PRINT '-----------------------------------------'
PRINT ' '
PRINT 'We found ' + cast(#NewMaxID as varchar(10)) + ' table(s) with the string '+#StringToFind
PRINT ' '
while(#NewMinID <= #NewMaxID)
Begin
select #SQLCommand = sqlcmd from #DataFoundInTables where ID = #NewMinID
PRINT #SQLCommand
SET #NewMinID = #NewMinID + 1
End
PRINT ' '
PRINT '-----------------------------------------'
End
This query was working fine one month ago but now it doesn't fetch the results . Can anyone tell me what is wrong in this query .
I'm trying to create a stored procedure to create all possible combination of a table with itself. For now, I got this code, but it produces the following error:
Syntax error: expected something between the word 'A' and the integer '2'
Code:
CREATE MULTISET TABLE PRUEBA
(
CAMPO VARCHAR(10)
);
INSERT INTO PRUEBA VALUES('A');
INSERT INTO PRUEBA VALUES('B');
INSERT INTO PRUEBA VALUES('C');
REPLACE PROCEDURE TEST()
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(255);
DECLARE i INT;
DECLARE n INT;
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || i ; -- Error in this part.
SET b = b || 'A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || i ;
SET b = b || 'AND A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
EXECUTE IMMEDIATE qry;
END;
CALL TEST();
I'd join the 'i' variable to create multiple alias for all cross tables.
Your i variable is an INTEGER. Try casting it as a VARCHAR() when you do your concatenations:
SET a = a || 'CROSS JOIN PRUEBA A' || CAST(i AS VARCHAR(2)) ; -- Error in this part.
SET b = b || 'A' || CAST((i-1) AS VARCHAR(2)) || '.CAMPO < A' ||
CAST(i AS VARCHAR(2)) || '.CAMPO';
You'll have to do this in the subsequent ELSE block as well.
Use explicit CAST or TRIM to avoid the leading blanks generated by implicit cast from INTEGER to VARCHAR. And you need to use a dynamic cursor to return the result of the SELECT to the caller.
REPLACE PROCEDURE TEST()
DYNAMIC RESULT SETS 1 --Allow returning data to caller
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(4096);
DECLARE i INT;
DECLARE n INT;
DECLARE csr1 CURSOR WITH RETURN FOR stmt1; --Declare a dynamic cursor
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'AND A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
PREPARE stmt1 FROM qry; --Prepare a dynamic SQL statement for the cursor
OPEN csr1; --Execute the SELECT statement
--Leave a WITH RETURN cursor open to return the result set
END;
if you're using bteq you might have to write the procedure into a file and load it with .compile directive.
once you are loggen in and supposing the file is /tmp/stored_procedure.sql
compile it like this:
.compile file='/tmp/stored_procedure.sql';
I need to create a mssql query, in that query i would like to put 8 parameters, they are:
table_primary_key : primary key column name,
table_name : table name,
start_row : starting from this row,
limit_row : end row,
column_name : where column name,
column_value : where column name = column value,
sort_by : sort by column name.
order : ASC / DESC.
note: the bold one is the one i haven't implemented yet.
my current query is this :
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (ORDER BY *sort_by*) as row
FROM *table_name*
) a
WHERE row > *start_row* AND row <= *limit_row*
my question is how I add table_primary_key, column_name, column_value, order to my current query?
my goal is make query display data from a table_name, start from
start_row until limit_row, where column_name = column_value. and the
data will be sort by sort_by and the order is according to order
if my question int clear enough please ask, thanks
You can try to use dynamic sql expression like this:
declare
#table_primary_key varchar(max) = 'ProjectID',
#table_name varchar(max) = 'ProjectList',
#start_row int = 10,
#limit_row int = 20,
#column_name varchar(max) = 'ProjectStatus',
#column_value varchar(max) = '5',
#sort_by varchar(max) = 'ProjectName',
#order varchar(4) = 'ASC' -- 'DESC'
declare
#sql varchar(max) = ''
set #sql = 'SELECT * FROM ( '
+ 'SELECT ' + #table_primary_key + ', ROW_NUMBER() OVER (ORDER BY ' + #sort_by + ' ' + #order + ') as row FROM ' + #table_name + ' WHERE ' + #column_name + ' = ''' + #column_value + ''') a'
+ ' WHERE row > ' + cast(#start_row as varchar) + ' and row <= ' + cast(#limit_row as varchar)
exec ( #sql )
Or you can use stored procedure
create procedure dbo.GetResults
(
#table_primary_key varchar(max),
#table_name varchar(max),
#start_row int,
#limit_row int,
#column_name varchar(max),
#column_value varchar(max),
#sort_by varchar(max),
#order varchar(4)
)
as
begin
declare
#sql varchar(max) = ''
set #sql = 'SELECT * FROM ( '
+ 'SELECT ' + #table_primary_key + ', ROW_NUMBER() OVER (ORDER BY ' + #sort_by + ' ' + #order + ') as row FROM ' + #table_name + ' WHERE ' + #column_name + ' = ''' + #column_value + ''') a'
+ ' WHERE row > ' + cast(#start_row as varchar) + ' and row <= ' + cast(#limit_row as varchar)
exec ( #sql )
end
and then...
exec GetResults 'ProjectID', 'ProjectList', 10, 20, 'ProjectStatus', '5', 'ProjectName', 'ASC'
I am using PostgreSQL 9.1
I have the following table containing some settings
setting | content
---------------+---------
enabled | True
reenable_time | 1
count_row | 6
count_col | 3
(4 rows)
And I want to have something like this
enabled | reenable_time | count_row | count_col
---------+-----------------+-------------+----------
True | 1 | 6 | 3
(1 row)
Thank you for your answers!
What you need is cross-tabulation (pivoting), aka turning rows into columns.
If you don't want to hardcode "enabled", "reenable_time", etc., you need to use dynamic SQL.
The basic idea goes like this:
SELECT -- Grab the user_account columns.
acc.id,
acc.email,
-- Use max() combined with a case statement to
-- usher individual attribute values into columns.
max(CASE WHEN (attr.attribute_type = 'first-name')
THEN attr.value END) AS fname,
max(CASE WHEN (attr.attribute_type = 'last-name')
THEN attr.value END) AS lname,
max(CASE WHEN (attr.attribute_type = 'title')
THEN attr.value END) AS title
FROM user_account AS acc
-- Join the attribute table /once/.
LEFT JOIN user_attribute AS attr
ON (attr.user_account_id = acc.id)
WHERE (acc.email = 'foo#example.com')
-- Group by the non-pivoted columns
GROUP BY acc.id,acc.email;
Here a link for further information:
https://sykosomatic.org/2011/09/pivot-tables-in-postgresql/
Here an example from my workplace (it's MS-SQL, but you'll get the idea, PostGre doesn't support the pivot command, it's MS proprietary, so you need to use "case when" with "group by"):
-- ===================================================
-- Author: Stefan Steiger
-- Create date: 14.04.2011
-- Last modified: 17.01.2012
-- Description: Übersetzung für Berichte
-- ===================================================
CREATE PROCEDURE [dbo].[sp_RPT_Report_Translation]
#in_mandant varchar(3)
,#in_sprache varchar(2)
,#in_stichtag varchar(50)
,#in_report_name nvarchar(1000)
AS
BEGIN
DECLARE
#strSQL NVARCHAR(MAX)
,#strReportName NVARCHAR(1000)
,#strPivotColumns NVARCHAR(MAX)
,#stichtag DATETIME
-- Abrunden des Eingabedatums auf 00:00:00 Uhr
SET #stichtag = CONVERT(DATETIME, #in_stichtag)
SET #stichtag = CAST(FLOOR(CAST(#stichtag AS Float)) AS DateTime)
SET #in_stichtag = CONVERT(varchar(50), #stichtag)
SET NOCOUNT ON;
SET #strReportName = REPLACE(#in_report_name, N'''', '''''')
-- http://geekswithblogs.net/baskibv/archive/2008/07/03/123567.aspx
SELECT
#strPivotColumns = COALESCE(#strPivotColumns, '') + '[' + [RTR_ItemCaption] + '], '
FROM T_RPT_Translations
WHERE (RTR_Status = 1)
AND (RTR_MDT_ID = #in_mandant)
AND
(
(RTR_ReportName = #strReportName)
OR
(RTR_ReportName = 'PARA_ALL')
)
--AND (RTR_ItemCaption != 'RPT_Title')
AND (RTR_ItemCaption IS NOT NULL)
AND
(
(RTR_IsFlag != 1)
OR
(RTR_IsFlag IS NULL)
)
AND (RTR_ItemCaption != '')
ORDER BY RTR_Sort
SET #strPivotColumns = SUBSTRING(#strPivotColumns, 0, LEN(#strPivotColumns))
SET #strPivotColumns = REPLACE(#strPivotColumns, N'''', '''''')
--PRINT #strPivotColumns
SET #strSQL = '
SELECT TOP(1) * FROM
(
SELECT
RTR_ItemCaption
--,RTR_Kurz_' + #in_sprache + '
,RTR_Lang_' + #in_sprache + '
FROM T_RPT_Translations
WHERE (RTR_MDT_ID = ''' + #in_mandant+ ''')
AND
(
(RTR_ReportName = ''' + #strReportName + ''')
OR
(RTR_ReportName = ''PARA_ALL'')
)
--AND (RTR_ItemCaption != ''RPT_Title'')
AND (RTR_Status = 1)
AND (RTR_ItemCaption IS NOT NULL)
AND
(
(RTR_IsFlag != 1)
OR
(RTR_IsFlag IS NULL)
)
AND (RTR_ItemCaption != '''')
) AS SourceTable
PIVOT
(
MAX(RTR_Lang_' + #in_sprache + ')
FOR RTR_ItemCaption IN
( '
+ #strPivotColumns +
' )
) AS PivotTable
--ORDER BY RPT_RM_SO_Bezeichnung, RPT_RM_GB_Bezeichnung, RPT_RM_NutzungGruppeCode
'
DECLARE #ProzedurParameter nvarchar(max)
SET #ProzedurParameter = '
DECLARE #in_mandant varchar(3)
,#in_sprache varchar(2)
,#in_stichtag varchar(50)
,#in_report_name nvarchar(1000)
;
SET #in_mandant = ''' + REPLACE(#in_mandant, '''', '''''') + ''';
SET #in_sprache = ''' + REPLACE(#in_sprache, '''', '''''') + ''';
SET #in_stichtag = ''' + REPLACE(#in_stichtag, '''', '''''') + ''';
SET #in_report_name = ''' + REPLACE(#in_report_name, '''', '''''') + ''';
'
EXECUTE sp_RPT_DEBUG_LOG_ProzedurRun
'sp_RPT_Report_Translation'
,#ProzedurParameter
,#strSQL
,'' --#ProzedurDetail
;
--PRINT #strSQL
EXECUTE (#strSQL)
END
GO