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
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;
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=#
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
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
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