SAS: Need to count number of instances per id - sql

Let's assume I have table1:
id value1 value2 value3
1 z null null
1 z null null
1 null y null
1 null null x
2 null y null
2 z null null
3 null y null
3 null null null
3 z null null
id value1 value2 value3
1 z null null
1 z null null
1 null y null
1 null null x
2 null y null
2 z null null
3 null y null
3 null null null
3 z null null
and I have table2:
id
1
2
3
I want to count number of values in each column per id to have output like this. (ex. id 1 has 2 - z's, one y and one x)
id value1 value2 value3
1 2 1 1
2 1 1 0
3 1 1 0
Need to do this in SAS. There is an example of this in Oracle but not in SAS.

If I understand correctly, this is a simple query using proc sql. For all the ids in the first table:
proc sql;
select id, count(val1) as val1, count(val2) as val2, count(val3 as val3)
from table1
group by id;
run;
count() counts the number of non-NULL values in a column or expression.

Related

SQL to fetch data using column values from one table as columns of another table

I have these two tables:
Org_Extra_Attr
org_id attr_name attr_path
1 desk_name str1
1 citizen bool1
2 perm_user bool1
3 skype_id str1
3 twitter str2
User_Attr_Values
org_id user_id str1 str2 str3 str4 bool1 bool2 bool3 bool4
1 1 b1d07 null null null 1 null null null
1 2 b2d01 null null null 0 null null null
2 3 null null null null 1 null null null
2 4 null null null null 1 null null null
3 5 sam_sky sam_twt null null null null null null
3 6 tom_sky tom_twt null null null null null null
So, the thing here is each org.can define max.of 4 extra attributes of type String and Boolean each, the Org_Extra_Attr table is like meta-data. For example org_id 1 has defined desk_name which will be str1's value for its users, whereas org_id 3 has skype_id which will be str1's value for its users.
This might be a bad design, but for now, I need to get users attribute names and values for a given org_id. Like for org_id = 1, I need a SQL query result(not a third table) like below:
user_id attr_name val
1 desk_name b1d07
1 citizen 1
2 desk_name b2d01
2 citizen 0
For org_id = 3
user_id attr_name val
5 skype_id sam_sky
5 twitter sam_twt
6 skype_id tom_sky
6 twitter tom_twt
Something like this
select
t2.user_id,
t1.attr_name,
CASE
WHEN t1.attr_path='str1' then t2.str1
WHEN t1.attr_path='str2' then t2.str2
WHEN t1.attr_path='str3' then t2.str3
WHEN t1.attr_path='str4' then t2.str4
WHEN t1.attr_path='bool1' then t2.bool1
WHEN t1.attr_path='bool2' then t2.bool2
WHEN t1.attr_path='bool3' then t2.bool3
WHEN t1.attr_path='bool4' then t2.bool4
END attr_value
FROM org_Extra_attr t1 inner join User_Attr_Values t2
on t1.org_id = t2.org_id
where t1.org_id=1
This is not an answer, but too long for a comment
That is a bad data model. You should not store column names in your tables.
What you could have instead is:
Org_Attr (PK = org_id + attr_no)
org_id attr_no attr_name type
1 1 desk_name STRING
1 2 citizen BOOL
2 1 perm_user BOOL
3 1 skype_id STRING
3 2 twitter STRING
Org_Attr_User (PK = org_id + attr_no + user_id)
org_id attr_no user_id value
1 1 1 b1d07
1 1 2 b2d01
1 2 1 1
1 2 2 0
2 1 3 1
2 1 4 1
3 1 5 sam_sky
3 1 6 tom_sky
3 2 5 sam_twt
3 2 6 tom_twt
With such a model data integrity would be guaranteed and querying, too, would be simple:
select oau.user_id, oa.attr_name, oau.value
from Org_Attr oa
join Org_Attr_User oau using (org_id, attr_no)
where org_id = 1;

Compare the column values where there are null and not null values

I want to compare the values from a table where there are null and not null values for the same ID ( If not null then I want minimum of two not null values). IF all the values are null for the given ID, I want the values to be displayed as null for the ID.
Input
ID Amount
1 Null
1 Null
1 Null
1 500
1 600
1 700
2 Null
2 Null
2 Null
2 Null
2 Null
3 Null
3 Null
3 300
3 600
3 200
Expected output
ID Amount
1 500 (min Not null value)
2 Null
3 200 (Min Not null value)
Simple grouping will do the trick:
select t.id, min(t.amount)
from table t
group by t.id

collapse staggered records to a single row for repeating keys

I want to collapse table to eliminate values in sql but the table has repeating keys. For example, I want to collapse this:
key1 key2 v1 v2 v3
1 A a NULL NULL
1 A NULL NULL 9
1 A NULL x NULL
1 A b NULL NULL
1 A NULL NULL 8
1 A NULL x NULL
1 A a NULL NULL
1 A NULL NULL 7
1 A NULL y NULL
1 A b NULL NULL
1 A NULL NULL 6
1 A NULL y NULL
1 B a NULL NULL
1 B NULL NULL 5
1 B NULL z NULL
1 B b NULL NULL
1 B NULL NULL 4
1 B NULL z NULL
1 C a NULL NULL
1 C NULL NULL 10
1 C z NULL
1 C b NULL NULL
1 C NULL NULL 11
1 C NULL z NULL
into this:
key1 key2 v1 v2 v3
1 A a x 9
1 A b x 8
1 A a y 7
1 A b y 6
1 B a z 5
1 B b z 4
1 C a z 10
1 C b z 11
Aggregate functions don't work and I haven't had success with self-join. Any idea?
You have a key/value table. This is something we usually avoid, but sometimes it cannot be avoided. Your original table looks something like this:
key1 key2 col value
1 A v1 a
1 A v1 a
1 A v1 a
1 A v1 a
1 A v1 b
1 A v1 b
1 A v1 b
1 A v1 b
1 A v2 x
1 A v2 x
1 A v2 y
1 A v2 y
...
I am showing the rows in another order then your query result, but that doesn't matter, for a table has no inherent order; it contains the data as an unordered set. We can see that for the same key 1|A|v1 the table contains diifferent values (four times 'a', four times 'b'). This is unexpected. Usually key value tables show one value per key.
So it may be that there is something wrong with your data model. Or the table has more columns, e.g. a date to show history data and also enable us to select the current value for 1|A|v1. Then you'd have to change your original query to take this into account. Or that data model is correct and 1|A|v1 does have four 'a' and four 'b', but then your expected query result makes no sense, for there is nothing to relate v1='a' to v2='x' for instance.
So something is wrong: datamodel, existing query, desired result. Find out which.
Have you tried "select distinct"
Select distinct key1, key2, v1, v2, v3
From SomeTable

Find values which are present in all columns in a Cable

I would like a SQL Server query which finds the Values in a cell which fills multiple columns. For example, if I have table
ID Value1 Value2 Value3
1 2 NULL NULL
1 NULL 3 NULL
1 NULL NULL 4
1 3.4 NULL NULL
2 NULL 3 NULL
2 NULL NULL NULL
3 NULL NULL 91
As in the table above, only 2 of the columns can be filled at a time(First is ID and 2nd is either of Value1, 2 or 3) and ID can be repeated multiple times.
I want to return the ID as only 1 because 1 is the only ID that populates all the three other columns. 2 fills only Value2 and all the other values of 2nd iteration of 2 are NULL where as 3 is present only in Column Value3. Is there someway that I can find the Id's which fill all the other columns.
I would love to do this preferably without a cursor but I can go for cursor if it's compulsory. Thanks
EDIT
Desired Table:
ID
1
The Statement should return only the filtered IDs which populate all the other columns.
Try this
SELECT id,
FROM TableName
GROUP BY id
HAVING MAX(value1) IS NOT NULL AND
MAX(value2) IS NOT NULL AND
MAX(value3) IS NOT NULL
Something for you try if you want some less lines of code:
select ID from dbo.Table_1 group by ID having count(Value1) > 0 AND count(Value2) > 0 AND count(Value3) > 0

Group multiple rows together

I have a table which contains the following and I am looking to group them to get the below output. Is it possible?
Input
ID Value1 Value2 Value3
5 Y NULL NULL
5 NULL 1 NULL
5 NULL NULL USA
5 NULL NULL NULL
6 N NULL NULL
6 NULL 2 NULL
6 NULL NULL GBP
6 NULL NULL NULL
Output
ID Value1 Value2 Value3
5 Y 1 USA
6 N 2 GBP
Group by the id and use max() to get the non-null value per each group
select id,
max(value1) as value1,
max(value2) as value2,
max(value3) as value3
from your_table
group by id
BTW you should think about changing you table design. It is not normalized.