Alter Table, Add Column and Set column value in one query? - sql

Is it possible to, in the same query, add a column to an existing table and set that column's value using case when?
ALTER TABLE #totalrevenue
ADD TotalRevenue_2003 Int CASE WHEN (Full2003 + Half2003 = 0) THEN NULL ELSE 1 END
FROM data.revenuesummary
WHERE #totalrevenue.ID = data.revenuesummary.ID'
Thanks!

What about using Computed columns?
Read more here:
https://msdn.microsoft.com/en-us/library/ms188300.aspx
Tiny example
CREATE TABLE dbo.#Products
(
ID int IDENTITY (1,1) NOT NULL
, Full2003 smallint
, Half2003 smallint
, TotalRevenue2003 AS IIF(Full2003 + Half2003 = 0, NULL, 1)
);
INSERT INTO dbo.#Products
(Full2003, Half2003)
VALUES
(2, 3),
(2, 2),
(2, -2)
SELECT *
FROM dbo.#Products
Results in:
ID Full2003 Half2003 TotalRevenue2003
1 2 3 1
2 2 2 1
3 2 -2 NULL

Related

Choose a record from the table where two of the default values are 0 or 1, a bit tricky

Looking for a more elegant and most logical solution for:
The table:
index
id
by_default
text
1
1
0
AAA
2
1
1
ABA
3
1
0
ABC
4
2
0
BCA
5
2
0
BCB
The task is to find the minimum index value with defaults set to 1 and/or defaults set to 0.
I have the following code (not very elegant, but it works, also very slow):
declare #byd_1 as int=
(select min(t.index) idx from Table t where t.[id]=1 and t.by_default=1)
declare #byd_2 as int=
(select min(t.index) idx from Table t where t.[id]=1 and t.by_default=0)
select (case when #byd_1 is null then #byd_2 else #byd_1 end)
The tricky part is: sometimes the by_default column is always 0 (for example: id:2 may have no by_default values set) and as mentioned earlier the task is: need to get the minimum value of the index column.
What is the most elegant (one-line) code possible?
Using MSSQL
The expected results, according to the sample table, should be the following:
index
id
by_default
text
2
1
1
ABA
4
2
0
BCA
Edited to add text also.
A bit ugly but:
drop table #t
select *
into #t
from (
VALUES (1, 1, 0, N'AAA')
, (2, 1, 1, N'ABA')
, (3, 1, 0, N'ABC')
, (4, 2, 0, N'BCA')
, (5, 2, 0, N'BCB')
) t (index_,id,by_default,text)
select index_, id, by_default, text
from (
select min(index_) OVER(PARTITION BY id) AS minIndex
, MIN(case when by_default = 1 then index_ end) over(partition by id) AS minIndexDefault
, *
from #t
) t
where isnull(minIndexDefault, minIndex) = index_

Automatically set SUM calculation's result as column value during / after row insert

I have an SQL table called "credits" which contain the following columns:
id (Serial ID for rows (1,2,3,....))
account_id (ID of associated client)
change (int4)
rolling_change
Every time during/after a row insert, I'd like the result of this Query to be the "rolling_change" column's value:
SELECT SUM(change)
FROM credits
WHERE account_id = {account_id} AND id < {this_id};
How can I make this process happen automatically on every row insert?
(I'm using DBeaver for reference)
Here's an example that updates the empty rolling_change after inserts.
CREATE TABLE credits (
id SERIAL PRIMARY KEY,
account_id INT NOT NULL,
change INT NOT NULL,
rolling_change INT
);
CREATE OR REPLACE FUNCTION calc_credits_rolling_change()
RETURNS trigger AS $calc_rolling_change$
BEGIN
UPDATE credits tgt
SET rolling_change = src.rolling_change
FROM (
SELECT id
, SUM(change) OVER (PARTITION BY account_id
ORDER BY id) AS rolling_change
FROM credits
) src
WHERE src.id = tgt.id
AND tgt.rolling_change IS NULL;
RETURN NEW;
END;
$calc_rolling_change$ LANGUAGE plpgsql;
CREATE TRIGGER trg_credits_rolling_change
AFTER INSERT
ON credits
EXECUTE PROCEDURE calc_credits_rolling_change();
INSERT INTO credits (account_id, change) VALUES
(1, 1), (1, 0)
, (2, 1), (2, 1), (2, 0);
INSERT INTO credits (account_id, change) VALUES
(3, 2), (3, 1), (1, 10)
select * from credits order by account_id, id;
id
account_id
change
rolling_change
1
1
1
1
2
1
0
1
8
1
10
11
3
2
1
1
4
2
1
2
5
2
0
2
6
3
2
2
7
3
1
3
Demo on db<>fiddle here

Add calculated column in Snowfalke

Again, I can't seem to find a simple way to do this.
But I've been coding for a while now and potentially I'm just tired and losing it!
SELECT
case when "colA" = '1' OR "colB" = 1 then 1
else 0
end as "colc"
FROM t1
How do I add this new column to t1, preserving the order etc.?
I know I can run
ALTER t1 ADD COLUMN colc
but how do I populate the values correctly?
Despite the documentation you can find around, it is actually possible to create computed columns. Here is an example:
create or replace table computedColTest (id bigint, id2 bigint, derived bigint as (id * id2));
insert into computedColTest values (3, 5);
select * from computedColTest;
The result is:
However, I don't think it is possible to directly translate the logic you need as you can't seem to be able to use a logical operator within it. You can however adapt it a bit to your situation and translate your switch into a mathematical operation that is compatible.
I think 'Virtual Columns' is how derived columns are known in Snowflake.
Check this out:
CREATE
OR REPLACE TABLE Virtual_Column_Example (
colA INT
, colB INT
, derived INT AS ( IFF(colA = 1 or colB = 1, 1, 0) )
);
INSERT INTO Virtual_Column_Example
VALUES (0, 0), (1, 1), (1, 2), (2, 1),(2, 2);
SELECT * FROM Virtual_Column_Example;
/*
---------------------
colA | colB | derived
---------------------
0 | 0 | 0
1 | 1 | 1
1 | 2 | 1
2 | 1 | 1
2 | 2 | 0
---------------------
*/
I actually found a way that works well, just use UPDATE
ALTER TABLE t1 ADD COLUMN "col3" INTEGER DEFAULT 0;
UPDATE t1
SET "col3"= 1
WHERE "col1" = 1 OR "col2" = 1;

Write a function or regular expression that will split string in sql

i have in sql table values in this way:
Id GameId GameSupplierId
1 1 NULL
2 2 NULL
3 3 1
4 3 2
5 3 3
What i want is to filter in sql procedure by GameId and if there is GameSupplierId by supplier too. I will get string from my web page in format GameID ; GameSupplierId. For example:
1; NULL
2; NULL
or if there is GameSupplier too
3;1
3;1,2
Also i want to have multiple choice for example like this:
1,2,3;1,2
In my sql query i will then filter like WHERE #GameID = Table.GameID (and also to check #GameSupplierId IN (,,,))
Just add your desired columns into ORDER BY:
ORDER BY t.GameId, t.GameSuplierId
For example:
DECLARE #table TABLE
(
ID INT,
GameId INT,
GameSuplierId INT NULL
)
INSERT INTO #table
(
ID,
GameId,
GameSuplierId
)
VALUES
(1, 1, NULL)
, (2, 2, NULL)
, (3, 3, 1)
, (4, 3, 2)
, (5, 3, 3)
SELECT
*
FROM #table t
ORDER BY t.GameId, t.GameSuplierId

How to increment a second primary key column in a table automatically when a new entry is added for the first primary key column

I am trying to find a way to increment a second primary key column in a table automatically when a new entry is added for the first primary key column. I suppose an example would be best here so here goes.
Suppose I have a table:
CREATE TABLE T
(
SecNum INT NOT NULL,
EntryID INT NOT NULL,
Value FLOAT,
) CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED
(
[SecNum] ASC,
[EntryID] ASC
)
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (0, 10)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (0, 10)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
0 1 10
I would run the following statement:
INSERT INTO T (SecNum, Value) VALUES (1, 20)
My table should look like:
SECNUM | ENTRYID | VALUE
-------------------------
0 0 10
0 1 10
1 0 20
This is possible using an INSTEAD OF trigger:
CREATE TRIGGER TriggerName
ON T
INSTEAD OF INSERT
AS
-- THIS TOP BIT IS OPTIONAL, IT WILL ALLOW ENTRY ID TO BE OVERRIDDEN IF
-- IT IS SUPPLIED TO THE INSERT AND WILL NOT VIOLATE THE PRIMARY KEY
IF NOT EXISTS
( SELECT 1
FROM T
INNER JOIN inserted i
ON i.SecNum = T.secNum
AND i.EntryID = T.EntryID
UNION
SELECT 1
FROM inserted
WHERE EntryID IS NULL
)
BEGIN
INSERT T (SecNum, EntryID, Value)
SELECT SecNum, EntryID, Value
FROM inserted
END
ELSE
-- IF OVERRIDE ABILITY IS NOT REQUIRED JUST USE THE BELOW INSERT
BEGIN
INSERT T (SecNum, EntryID, Value)
SELECT i.SecNum, COALESCE(LastID, 0), i.Value
FROM inserted I
LEFT JOIN
( SELECT SecNum, MAX(T.EntryID) + 1 [LastID]
FROM T
GROUP BY SecNum
) T
ON T.SecNum = i.SecNum
END
Example here
HOWEVER this is not very elegant. It could be worth asking is it really necessary? Could you get away with using a surrogate primary key, and use ROW_NUMBER() to create Entry ID's on the fly?
How about something like this:
INSERT INTO T (SecNum, Value, EntryId)
SELECT 0, 10, count(*)
FROM T WHERE SecNum = 0
It is not the cleanest solution and will perform pretty poorly too. But it should get the job done.
This is how to do it without storing the value in the table (I'm not sure why you want to store it)
TABLE
DECLARE #T TABLE
(
SecNum INT NOT NULL,
EntryID INT,
Value FLOAT
)
DATA
INSERT INTO #T
( SecNum, Value )
VALUES ( 0, 10 )
INSERT INTO #T
( SecNum, Value )
VALUES ( 0, 10 )
INSERT INTO #T
( SecNum, Value )
VALUES ( 1, 20 )
QUERY
SELECT SecNum,
ROW_NUMBER() OVER ( PARTITION BY value ORDER BY Value ) - 1 AS EntryID,
Value
FROM #T
RESULT
SecNum EntryID Value
0 0 10
0 1 10
1 0 20
If the EntryID changes with SecNum AND Value use this query:
SELECT SecNum,
ROW_NUMBER() OVER ( PARTITION BY Value,SecNum ORDER BY Value, SecNum ) - 1 AS EntryID,
Value
FROM #t
RESULT 2
SecNum EntryID Value
0 0 10
0 1 10
1 0 10
1 0 20
Your problem can be solved by using an instead of insert trigger
create trigger Trigger1 on T INSTEAD OF INSERT
as
begin
insert into T(SecNum,EntryID,Value)
select SecNum,
(select count(*) from T where SecNum = i.SecNum) as EntryID,
value
from inserted i
end