I'm trying to write queries that can loop new columns to selected number, such as 100 or 200 new columns, which use data from the previously created columns.
I have data like below:
IF NOT EXISTS
(
SELECT * FROM sysobjects WHERE name = 'test' AND xtype = 'U'
)
CREATE TABLE test
(
[id] INT,
[a] NUMERIC(3, 2),
[b] NUMERIC(3, 2)
);
INSERT INTO test
VALUES (1, 0.1, 0.7),
(2, 0.5, 0.5),
(3, 0.5, 0.3),
(4, 0.6, 0.5),
(5, 0.5, 0.5),
(6, 0.5, 0.67),
(7, 0.5, 0.5),
(8, 0.46, 0.5),
(9, 0.5, 0.5),
(10, 0.37, 0.52),
(11, 0.37, 0.37),
(12, 0.28, 0.2);
I have id, a, and b as input, and I want to create new columns as c c = a b, then d = a b c and so on, to even 100 or 200 new columns.
I could use queries like the one below, but if I need 100 columns, it will take forever to write.
select
t.*,
t.a t.b t.c d
from
(select
*,
a b c
from test) t;
I know that SQL is not good at loops, but I still want to try if it even possible.Thank you.
CodePudding user response:
The specifics of your problem indicate the database design is terrible, you'd never want to sum across columns like that. But your question about whether in SQL you can tell it to sort of write itself so that it'll save you from typing it all out, is generally no.
In some cases, database systems will support something like EXCEPT
(or since Snowflake likes to be different, EXCLUDE
)
That is helpful because you can SELECT * EXCEPT col1
which is sort of what you're looking for, though you're wanting to do that with a SUM
.
In general, no the language does not support such things. You might get lucky in some cases, where an RDBMS adds a helpful function for something that lots of users want to do (like in the case of EXCEPT)
Therefore, if you really want to do it, you have to look outside of SQL and build it yourself. For me personally, I run my SQL through a jinja engine that will parse out the SQL for me.
I actually have a custom wrapper that does the exact thing you want:
SELECT *,
({{ variables | join(' ') }}) AS SUM_OF_ALL
FROM {{ source_table }}
This is essentially a function that I have to pass a list of column names into it - so if I had 200 it would still be annoying. However using macros and other things it is definitely possible, to have it dynamically find all the column names so they don't have to be declared explicitly.
TL;DR - no, not possible without going outside of SQL.
CodePudding user response:
Here you go:
IF NOT EXISTS
(
SELECT * FROM sysobjects WHERE name = 'test' AND xtype = 'U'
)
CREATE TABLE test
(
[id] INT,
[a] NUMERIC(3, 2),
[b] NUMERIC(3, 2)
);
INSERT INTO test
VALUES (1, 0.1, 0.7),
(2, 0.5, 0.5),
(3, 0.5, 0.3),
(4, 0.6, 0.5),
(5, 0.5, 0.5),
(6, 0.5, 0.67),
(7, 0.5, 0.5),
(8, 0.46, 0.5),
(9, 0.5, 0.5),
(10, 0.37, 0.52),
(11, 0.37, 0.37),
(12, 0.28, 0.2);
DECLARE @sql nvarchar(max) = 'select t.*'
;WITH cte AS (
SELECT TOP 100 row_number() OVER(ORDER BY (SELECT NULL)) AS cnt
FROM sys.objects so CROSS JOIN sys.columns sc
)
SELECT @sql = @sql '
, 0' ' (t.a t.b) * (POWER(2.0, ' CAST(c.cnt as varchar(30)) '-1)) as c' cast(c.cnt AS varchar(300))
FROM cte c
SELECT @sql = @sql ' from test t'
SELECT @sql
EXEC (@sql)
EDIT: This code loops 100 columns or so and generate sums for previous column in a new column. The sums get pretty big after a while. Maybe i'm doing something wrong but not sure :)