I have a table that will have a variable number of columns based on my initial input. Is there a function to sum all the numeric columns of this table without specifying the name of each column?
Right now I have each column name hard coded in a proc sql command.
CREATE TABLE &new_table_name AS
(SELECT SUM(CASE WHEN col1 = &state THEN 1 ELSE 0 END) AS month_01,
SUM(CASE WHEN col2 = &state THEN 1 ELSE 0 END) AS month_02,
SUM(CASE WHEN col3 = &state THEN 1 ELSE 0 END) AS month_03,
SUM(CASE WHEN col4 = &state THEN 1 ELSE 0 END) AS month_04,
SUM(CASE WHEN col5 = &state THEN 1 ELSE 0 END) AS month_05
);
Sample input would be like this:
name m1 m2 m3 m4
aa 1 7 7 1
ab 2 4 2
ac 1 1
ad 1 3 1 1
ae 2 1 3
Then the sample output would be
name m1 m2 m3 m4
7 16 13 2
You are looking for PROC MEANS. Or really any summarization proc.
data have;
infile datalines missover;
input name $ m1 m2 m3 m4;
datalines;
aa 1 7 7 1
ab 2 4 2
ac 1 1
ad 1 3 1 1
ae 2 1 3
;;;;
run;
proc means data=have;
output out=want sum=;
run;
And the class statement would let you group by state or whatever. WHERE also works fine in PROC MEANS to filter.
Leaving the var statement off calls for all numeric variables, or you can put in a var statement to limit, such as
var m1-m4;
as Reeza notes in comments.
Related
I have 2 tables like this
EmployeeID
LeaveTypeID
1
1
2
2
1
2
1
2
Now I want a TRIGGER that calculate automatically total of type 1 and type 2 in below table
EmployeeID
Type1
Type2
1
1
2
2
0
1
No need for triggers. Just create a view that has the aggregation in it
CREATE VIEW vTotal
AS
SELECT
t.EmployeeID,
Type1 = COUNT(CASE WHEN t.LeaveTypeID = 1 THEN 1 END),
Type2 = COUNT(CASE WHEN t.LeaveTypeID = 2 THEN 1 END)
FROM dbo.YourTable t
GROUP BY
t.EmployeedID;
Sorry, not sure how to best word this so I'll just give an example.
1 VA b x 10
2 VA g y 5
3 VA b x 6
4 VA s y 7
5 VA s x 8
6 PA b y 1
7 PA s x 4
8 PA g y 5
9 PA s x 6
10 PA b y 9
I would like to summarize the above data like the following:
x_b x_s x_g y_b y_s y_g
VA 16 8 0 9 7 0
PA 0 10 0 9 0 5
where I have a row for each state and combinations of the two groups (group of x, y and group of b,s,g) across the top and summarize the values for all groupings like that.
What is the best way to do this in SQL?
Thanks!
You can do this using conditional aggregation:
proc sql;
select state,
sum(case when col3 = 'b' and col4 = 'x' then col5 else 0 end) as x_b,
sum(case when col3 = 's' and col4 = 'x' then col5 else 0 end) as x_s,
sum(case when col3 = 'g' and col4 = 'x' then col5 else 0 end) as x_g,
sum(case when col3 = 's' and col4 = 'y' then col5 else 0 end) as y_s,
sum(case when col3 = 'g' and col4 = 'y' then col5 else 0 end) as y_g
from t
group by state;
Don't do this in SQL. You're in SAS, use the tools you have: here PROC TABULATE is the best tool.
data have;
input obs state $ var1 $ var2 $ val;
datalines;
1 VA b x 10
2 VA g y 5
3 VA b x 6
4 VA s y 7
5 VA s x 8
6 PA b y 1
7 PA s x 4
8 PA g y 5
9 PA s x 6
10 PA b y 9
;;;;
run;
proc tabulate data=have;
class state var1 var2;
var val;
tables state, var1=' '*var2=' '*val=' '*sum=' '/printmiss misstext='0';
run;
If you want a dataset and not a printed table, that's easy enough to do. Just make a dataset from TABULATE, then make a few minor changes and transpose it.
proc tabulate data=have out=want_first;
class state var1 var2;
var val;
tables state, var1=' '*var2=' '*val=' '*sum=' '/printmiss misstext='0';
run;
data want_pret;
set want_first;
var_name = catx('_',var2,var1);
value = coalesce(val_sum,0);
keep state var_name value;
run;
proc transpose data=want_pret out=want;
by state;
id var_name;
var value;
run;
Notice that none of this requires hardcoding the values for any of the variables - no matter what you put in var1/var2, this will always give you the right result.
If you want to make a cross-tab use PROC FREQ. Use the WEIGHT statement to pass in the exiting counts and the SPARSE option to get the zeros output.
proc freq data=have ;
tables state*v2*v1 / noprint out=counts sparse ;
weight cnt ;
run;
You can then turn the result into your horizontal format by using PROC TRANSPOSE.
proc transpose data=counts delimiter=_
out=want(drop= _name_ _label_)
;
by state ;
id v2 v1 ;
var count ;
run;
I am building a report and I am stuck formulating a query. I am bringing the following data from multiple tables after a lot of joins.
ID TYPE RATING
----- ---- ------
ID_R1 A 1
ID_R1 B 3
ID_R2 A 2
ID_R2 B 1
ID_R3 A 4
ID_R3 B 4
ID_R4 A 2
ID_R4 B 3
ID_R5 A 2
ID_R5 B 3
What actually is happening is that Every ID will have a Rating for Type A & B so what I need to do is transform the above into the following
ID Type_A_Rating Type_B_Rating
----- ------------- -------------
ID_R1 1 3
ID_R2 3 1
ID_R3 4 4
ID_R4 2 3
ID_R5 2 3
I have think group by and different techniques but so far I am unable to come up with a solution. Need help F1! F1!
p.s just for the record my end game is getting the count of (A,B) combinations
Type_A_Rating Type_B_Rating Count
------------- ------------- -----
1 1 0
1 2 0
1 3 1
1 4 0
2 1 0
2 2 0
2 3 2
2 4 0
3 1 1
3 2 0
3 3 0
3 4 0
4 1 0
4 2 0
4 3 0
4 4 1
From this you can see that a simple GROUP BY with any form AND OR conditions doesn't suffice until I get the data as mentioned. I could use two intermediate/temp tables, in one get Type_A_Rating with ID and then in second Type_B_Rating with ID and then in another combine both but isn't there a better way.
This should work as SQL engine agnostic solution (provided that there is exactly one row with type A for each ID and one row with type B for each ID):
select
TA.ID,
TA.RATING as Type_A_Rating,
TB.RATING as Type_B_Rating
from
(select ID, RATING
from T where TYPE = 'A') as TA
inner join
(select ID, RATING
from T where TYPE = 'B') as TB
on TA.ID = TB.ID
Related SQL Fiddle: http://sqlfiddle.com/#!9/7e6fd9/2
Alternative (simpler) solution:
select
ID,
sum(case when TYPE = 'A' then RATING else 0 end) as Type_A_Rating,
sum(case when TYPE = 'B' then RATING else 0 end) as Type_B_Rating
from
T
group by
ID
Fiddle: http://sqlfiddle.com/#!9/7e6fd9/3
EDIT:
The above is correct but both can be simplified a bit:
select TA.ID, TA.RATING as Type_A_Rating, TB.RATING as Type_B_Rating
from T TA join
T TB
on TA.ID = TB.ID AND A.type = 'A' and B.type = 'B';
And (because I prefer NULL when there are no matches:
select ID,
max(case when TYPE = 'A' then RATING end) as Type_A_Rating,
max(case when TYPE = 'B' then RATING end) as Type_B_Rating
from T
group by ID
I have following table structure
ID Status1 status 2 status 3
A1 1 0 1
A1 1 1 0
A2 1 0 0
A3 0 1 1
I want to collect it as one record like this (only 1's count for each column)
A1 2 1 1
A2 1 1 0
A3 0 1 1
I have tried using pivot but actually not the one am getting it correctly.
Please give some thought.
Hope you looking for this
Select ID, SUM(Status1) As Status1, SUM(Status2) As Status2, SUM(Status3) As Status3
from MyTable
Group By ID
I have a typical situation.
my table has four column. (id, user, col2, status)
I want to write a query which gives me the results of col2. But it has a column status which has (0/1). So I want only col2 data which has 0 status + a user's all data (0/1).
id user col2 status
1 sam aa 1
2 sam bb 0
3 sam cc 1
4 max dd 0
5 max dd 1
6 max ee 1
7 jam ff 0
8 jam gg 1
My result should be like. I want sam's all result + other's only 0 status result.
id user col2 status
1 sam aa 1
2 sam bb 0
3 sam cc 1
4 max dd 0
7 jam ff 0
How about
SELECT * FROM yourTable WHERE user = "sam" OR status = 0;
?
your where condition would be:
where (user = 'sam' or status = 0)
select * from the_table where user = 'sam' or status = 0 order by id
select *
from yourtable as t
where t.user = "sam"
or t.status = 0
SELECT *
FROM YOUR_TABLE
WHERE user = 'sam' OR
status = 0
We use OR in the WHERE clause so that it will be true for all of sam's rows and for all other rows which have status as 0