Sum all Inserted Values in Trigger - sql

Suppose, I have the following table T1:
| type | col1 | col2 |
|------|------|------|
| abc | 0 | 0 |
| def | 0 | 3 |
| abc | 3 | 123 |
| def | 0 | 5 |
| def | 2 | 4 |
Periodically, some new values are inserted into T1. I now want to create a trigger, which populates another table T2, depending on the values inserted into T1.
The values to insert into T2 can be calculated using the following pseudo code:
IF col1 = 0 AND col2 = 0
A++
ELSE IF col1 = 0 col2 > 0
B++
ELSE IF col1 > 0
C++
I already created the following trigger:
Create TRIGGER TRI1
ON dbo.T1
FOR INSERT
AS
BEGIN
INSERT INTO dbo.T2
SELECT Sum(CASE WHEN col1 = 0 AND col2 = 0 THEN 1 END) as 'A',
Sum(CASE WHEN col1 = 0 AND col2 > 0 THEN 1 END) as 'B',
Sum(CASE WHEN col1 > 0 THEN 1 END) as 'C'
FROM INSERTED
END
When I test it with:
INSERT INTO dbo.T1 VALUES ('abc',2,3)
INSERT INTO dbo.T1 VALUES ('abc',0,0)
INSERT INTO dbo.T1 VALUES ('def',0,3)
INSERT INTO dbo.T1 VALUES ('abc',0,0)
I get the following output:
| A | B | C |
|------|------|------|
| NULL | NULL | 1 |
| 1 | NULL | NULL |
| NULL | 1 | NULL |
| 1 | NULL | NULL |
But the expected output is only 1 row per insert operation:
| A | B | C |
|---|---|---|
| 2 | 1 | 1 |

You should create a trigger like this,
CREATE TRIGGER TRI1 ON dbo.T1
FOR INSERT
AS
BEGIN
IF EXISTS (
SELECT 1
FROM dbo.T2
)
BEGIN
UPDATE T
SET A = Sum(CASE
WHEN T.col1 = 0
AND T.col2 = 0
THEN 1
ELSE 0
END)
,B = Sum(CASE
WHEN T.col1 = 0
AND T.col2 > 0
THEN 1
ELSE 0
END)
,C = Sum(CASE
WHEN T.col1 > 0
THEN 1
ELSE 0
END)
FROM dbo.t1 T
END
ELSE
BEGIN
INSERT INTO dbo.T2
SELECT Sum(CASE
WHEN T.col1 = 0
AND T.col2 = 0
THEN 1
ELSE 0
END) AS 'A'
,Sum(CASE
WHEN T.col1 = 0
AND T.col2 > 0
THEN 1
ELSE 0
END) AS 'B'
,Sum(CASE
WHEN T.col1 > 0
THEN 1
ELSE 0
END) AS 'C'
FROM dbo.t1 T
END
END

Related

SQL - How to count the number of empty and non-empty columns per record?

I have a table that contains 4 columns and I want to create two new columns that count respectively
the number of non-empty (Count_1) and
the number of blanks/empty (Count_2)
in the first 4 columns.
In other words, this is my input:
Column1 | Column2 | Column3 | Column4
X | X | . | Y
. | . | Y | X
. | . | . | .
and this is the desired output:
Column1 | Column2 | Column3 | Column4 | Count_1 | Count_2
X | X | . | Y | 3 | 1
. | . | Y | X | 2 | 2
. | . | . | . | 0 | 4
Is there any simple solution to this that allows to obtain this output in a single step?
In SQL you can use case expressions:
select t.*,
((case when column1 is not null then 1 else 0 end) +
(case when column2 is not null then 1 else 0 end) +
(case when column3 is not null then 1 else 0 end) +
(case when column4 is not null then 1 else 0 end)
) as count_1,
((case when column1 is null then 1 else 0 end) +
(case when column2 is null then 1 else 0 end) +
(case when column3 is null then 1 else 0 end) +
(case when column4 is null then 1 else 0 end)
) as count_2
from t;

pivoting table in postgresql

what i have
customerid status
Ax 1
Bx 3
Cx 5
Dx 4
Ex 2
i am looking to pivot above table.
What i need
customerid status_1 status_2 status_3 status_4 status_5
Ax 1 0 0 0 0
Bx 0 0 1 0 0
Cx 0 0 0 0 1
Dx 0 0 0 1 0
Ex 0 1 0 0 0
select customerid,
case when status = 1 then 1 else 0 end as status_1,
case when status = 2 then 1 else 0 end as status_2,
case when status = 3 then 1 else 0 end as status_3,
case when status = 4 then 1 else 0 end as status_4,
case when status = 5 then 1 else 0 end as status_5
from your_table
order by customerid;
Using tablefunc module in Postgres
postgres=# create extension tablefunc ;
CREATE EXTENSION
postgres=# create table your_table (customerid char(2),status int);
insert into your_table values('Ax',1),('Bx',3),('Cx',5),('Dx',4),('Ex',2);
CREATE TABLE
INSERT 0 5
postgres=# SELECT * FROM crosstab(
$$select customerid, status,
count(status) AS "# of status"
from your_table group by customerid, status
order by customerid,status$$ ,
$$select distinct status from your_table
order by status$$)
AS ("customerid" text,
"status_1" text, "status_2" text, "status_3" text,
"status_4" text, "status_5" text);
customerid | status_1 | status_2 | status_3 | status_4 | status_5
------------+----------+----------+----------+----------+----------
Ax | 1 | | | |
Bx | | | 1 | |
Cx | | | | | 1
Dx | | | | 1 |
Ex | | 1 | | |
(5 rows)
postgres=#

Get column with two two rows having specific values

I have a table that looks like this:
| col1 | col2 |
|------|------|
| a | 1 |
| a | 2 |
| a | 3 |
| b | 1 |
| b | 3 |
| c | 1 |
| c | 2 |
I need to find the value of col1 where two rows with the same col1 value exist that has a col2 value of 1 and 2
results would be:
| col1 |
|------|
| a |
| c |
You can filter the rows with the col2 values you want, then group by col1 and only take the groups with count = 2
select col1
from yourTable
where col2 in (1, 2)
group by col1
having count(distinct col2) = 2
Another solution would be
select col1
from your_table
group by col1
having sum(case when col2 = 1 then 1 else 0 end) > 0
and sum(case when col2 = 2 then 1 else 0 end) > 0

Update multiple columns from one table with one column from another table

I have three tables that are structured in this format:
DECLARE #A
(
TypeName varchar(100),
Type1 varchar(3),
Type2 varchar(3),
Type3 varchar(3),
Type4 varchar(3),
Type5 varchar(3),
Type6 varchar(3)
)
Data:
| Bob | null | null | null | null | null | null |
| Steve | null | null | null | null | null | null |
| Bill | null | null | null | null | null | null |
...
DECLARE #B
(
NameID int,
Name varchar(100)
)
Data:
| 1 | Bob |
| 2 | Steve |
| 3 | Bill |
...
DECLARE #C
(
NameID int,
Type int
)
Data:
| 1 | 1 |
| 1 | 3 |
| 2 | 1 |
| 3 | 2 |
...
I want to update the Type# columns in table #A with a condition based on the Type column of table #C. Here is an SQL query that I have attempted to use:
UPDATE #A SET
Type1 = (CASE WHEN c.Type = 6 THEN 'Yes' ELSE 'No' END),
Type2 = (CASE WHEN c.Type = 1 THEN 'Yes' ELSE 'No' END),
Type3 = (CASE WHEN c.Type = 2 THEN 'Yes' ELSE 'No' END),
Type4 = (CASE WHEN c.Type = 3 THEN 'Yes' ELSE 'No' END),
Type5 = (CASE WHEN c.Type = 4 THEN 'Yes' ELSE 'No' END),
Type6 = (CASE WHEN c.Type = 5 THEN 'Yes' ELSE 'No' END),
FROM #A
INNER JOIN #B b ON b.Name = TypeName
INNER JOIN #C c ON c.NameID = b.NameID
SELECT * FROM #A
Instead of getting the expected values:
| Bob | No | Yes | No | Yes | No | No | <-- Correct
| Steve | No | Yes | No | No | No | No |
| Bill | No | No | Yes | No | No | No |
I get these values:
| Bob | No | Yes | No | No | No | No | <-- Incorrect (noticed the third column from the right being set to No instead of Yes)
| Steve | No | Yes | No | No | No | No |
| Bill | No | No | Yes | No | No | No |
I have also tried re-writing the statement to be like this:
UPDATE #A SET
Type1 = (CASE WHEN t.Type = 6 THEN 'Yes' ELSE 'No' END),
Type2 = (CASE WHEN t.Type = 1 THEN 'Yes' ELSE 'No' END),
Type3 = (CASE WHEN t.Type = 2 THEN 'Yes' ELSE 'No' END),
Type4 = (CASE WHEN t.Type = 3 THEN 'Yes' ELSE 'No' END),
Type5 = (CASE WHEN t.Type = 4 THEN 'Yes' ELSE 'No' END),
Type6 = (CASE WHEN t.Type = 5 THEN 'Yes' ELSE 'No' END),
FROM
(
SELECT b.Name, c.Type
FROM #C c
INNER JOIN #B b on b.NameID = c.NameID
) t
WHERE t.Name = TypeName
But it still returned the latter results.
So why is it that the columns are not being updated correctly for the TypeName column Bob and how would I fix that so that I can get my expected values?
The problem is that you have several rows in #C per person. You'll have to first make it one row to be able to update the data:
select
NameID,
max(case Type when 1 then 1 else 0 end) as Type1,
max(case Type when 2 then 1 else 0 end) as Type2,
max(case Type when 3 then 1 else 0 end) as Type3,
max(case Type when 4 then 1 else 0 end) as Type4,
max(case Type when 5 then 1 else 0 end) as Type5,
max(case Type when 6 then 1 else 0 end) as Type6
from
#C
group by
NameID
Can't test this now, but you probably can even make the text there, with something like this:
case when max(case Type when 1 the 1 else 0) = 1 then 'Yes' else 'No'
end as Type1
You can use this as derived table in the update, or maybe collect the results first into another table variable

SQL Check if ungroup column values match

I have a sql table with following values
| col1 | col2| source | values
| 1 | 2 | A | null
| 1 | 2 | B | 1.0
| 1 | 2 | C | null
| 1 | 4 | A | 2.0
| 1 | 4 | B | 2.0
| 1 | 4 | C | 2.0
| 1 | 5 | A | null
| 1 | 5 | B | null
| 1 | 5 | C | null
How can I get an output with a group by of col1 and col2 with a flag:
all values match for a group ( flag = 1)
all values are null ( flag = 2)
some values is null (flag = 3)
Output:
| col1 | col2| flag
| 1 | 2 | 3
| 1 | 4 | 1
| 1 | 5 | 2
Or: based on your updated question:
SELECT
col1,
col2,
SUM(CASE WHEN SomeConditionHere THEN 1 ELSE 0 END) AS Flag
FROM Table1
GROUP BY col1, col2;
SQL Fiddle Demo
This will give you:
| COL1 | COL2 | FLAG |
----------------------
| 1 | 2 | 2 |
| 1 | 4 | 0 |
| 1 | 5 | 3 |
Note that: I assumed that the flag is how many NULL values are in the VALUES column, so I used "Values" IS NULL instead of SomeConditionHere.
I couldn't understand how the flag should be computed in the expected results you posted. You have to use the predicate that define your flag instead of "Values" IS NULL.
Update:
Try this:
WITH Flags
AS
(
SELECT
col1, col2,
COUNT(*) ValuesCount,
SUM(CASE WHEN "Values" IS NULL THEN 1 ELSE 0 END) AS NULLValues
FROM Table1
GROUP BY col1, col2
)
SELECT
col1,
col2,
Flag = CASE WHEN ValuesCount = NULLValues THEN 2
WHEN NULLVALUES = 0
AND ValuesCount = (SELECT COUNT(*)
FROM Table1 t2
WHERE t1.col1 = t2.col1
AND t1.col2 = t2.col2) THEN 1
ELSE 3
END
FROM Flags t1;
Updated SQL Fiddle Demo
This will give you:
| COL1 | COL2 | FLAG |
----------------------
| 1 | 2 | 3 |
| 1 | 4 | 1 |
| 1 | 5 | 2 |
In SQLServer2005+
;WITH cte AS
(
SELECT col1, col2, [values],
COUNT(CASE WHEN [values] IS NULL THEN 1 END) OVER(PARTITION BY col1, col2) AS cntNULL,
COUNT(*) OVER(PARTITION BY col1, col2) AS cntCol
FROM dbo.test5
)
SELECT col1, col2, MAX(CASE WHEN cntNULL = 0 THEN 1
WHEN cntNULL = cntCol THEN 2
ELSE 3 END) AS flag
FROM cte
GROUP BY col1, col2
Demo on SQLFiddle
...And solution without CTE if you want more portable SQL:
select col1,
col2,
case
when DistinctValuesWithoutNulls = 1 and NullCount = 0 then 1
when DistinctValuesWithoutNulls = 0 then 2
when NullCount > 0 then 3
end flag
from
(
select col1,
col2,
count(distinct [values]) DistinctValuesWithoutNulls,
sum(case when [values] is null then 1 else 0 end) NullCount
from Table1
group by col1, col2
) tmp