Row wise and conditions average in sql - sql

Below table input
Atm_ID
C1
C2
C3
C4
C5
R12673
2
5
3
1
10
R34721
3
5
2
1
8
R27835
1
2
2
8
6
I found the average Atm_Id wise but consider the data greater than equal 3 only and divide also count of number of greater than equal 3.
I need following output
Atm_ID
Average
R12673
6
R34721
5.33
R27835
7
Please any one to help me

You can simply use a CTE to generate a temp table and then can generate your desired table -
WITH CTE AS (SELECT Atm_ID,
CASE WHEN C1 >= 3 THEN C1 ELSE 0 END C1,
CASE WHEN C2 >= 3 THEN C2 ELSE 0 END C2,
CASE WHEN C3 >= 3 THEN C3 ELSE 0 END C3,
CASE WHEN C4 >= 3 THEN C4 ELSE 0 END C4,
CASE WHEN C5 >= 3 THEN C5 ELSE 0 END C5,
CASE WHEN C1 >= 3 THEN C1 ELSE 1 END +
CASE WHEN C2 >= 3 THEN C2 ELSE 0 END +
CASE WHEN C3 >= 3 THEN C3 ELSE 0 END +
CASE WHEN C4 >= 3 THEN C4 ELSE 0 END +
CASE WHEN C5 >= 3 THEN C5 ELSE 0 END tot_avg
)
SELECT Atm_ID, (C1 + C2 + C3 + C4 + C5)/tot_avg Average
FROM CTE;

Related

Union fields in a query

I have a table with fields A1, A2, A3, A4, B1, B2, B3 and B4. I need a select statement that union field : A1 and B1 in C1, A2 and B2 in C2,A3 and B3 in C3,A4 and B4 in C4
for example:
TABLE ONE
A1 A2 A3 A4 B1 B2 B3 B4
1 1 1 1 0 0 0 0
2 2 2 2 0 0 0 0
0 0 0 0 3 3 3 3
I need a result like this:
TABLE TWO
C1 C2 C3 C4
1 1 1 1
2 2 2 2
3 3 3 3
You need something like this
select A1, A2, A3, A4
from yourtable where a1+a2+a3+a4 > 0
union all
select B1, B2, B3, B4
from yourtable where b1+b2+b3+b4 > 0
should be easy like:
SELECT A1 AS C1
,A2 AS C2
,A3 AS C3
,A4 AS C4
FROM table_one
WHERE A1 != 0
AND A2 != 0
AND A3 != 0
AND A4 != 0
UNION ALL
SELECT B1 AS C1
,B2 AS C2
,B3 AS C3
,B4 AS C4
FROM table_two
WHERE B1 != 0
AND B2 != 0
AND B3 != 0
AND B4 != 0

T-SQL - having arithmetic deficiency syndrome

DECLARE #Table TABLE (CID int, C1 varchar(5), C2 decimal(18,6), C3 decimal(18,6))
INSERT INTO #Table
SELECT 1,'A',0.0,0.0
UNION ALL
SELECT 2,'A',0.1,0.0
UNION ALL
SELECT 3,'A',0.1,0.1
UNION ALL
SELECT 4,'B',0.0,0.0
UNION ALL
SELECT 5,'B',0.1,0.0
UNION ALL
SELECT 6,'B',0.1,0.1
SELECT * FROM #Table
WHERE C1 NOT IN ('B') AND (C2 >= 0 AND C3 >= 0)
/* Desired output
CID C1 C2 C3
1 A 0.0 0.0
2 A 0.1 0.0
3 A 0.1 0.1
4 B 0.0 0.0
*/
If C2 and C3 are greater than 0 then no record with C1 = B should be returned. I'm having trouble figuring out the logic. I can't seem to figure out the arithmetic. :(
Thank you
p.s. a non-subquery sln would be awesome!
Your logic is: "do not include the record if C2 > 0 AND C3 > 0 AND C1 = 'B'"
Negate it, which results in: C2 <= 0 OR C3 <= 0 OR C1 <> 'B' and use this condition to include all of the other records.
Note, if you meant to exclude records where (C2 > 0 OR C3 > 0) AND C1 = 'B', then you would negate that to include the other records: (C2 <= 0 AND C3 <= 0) OR C1 <> 'B'
Inclusive, consider the rows you do want:
SELECT * FROM #Table WHERE (C1 NOT IN ('B')) OR (C2 <= 0 AND C3 <= 0)
Exclusive, consider the rows you do not want:
SELECT * FROM #Table WHERE NOT (C1 IN ('B') AND (C2 > 0 OR C3 > 0))
These are algebraically equivalent, so pick the one that reads best.

Average across multiple columns with varying data

I have 10 decimal columns and I would like to add a computed column to my table that contains the average of these 10. A complication is that not every record has all 10 columns filled in. Some records have 4 some have 8 and some have 10.
e.g.
ID D1 D2 D3 D4 D5 D6 D7 D8 D9 D10
1 12 19 13 14
2 32 53 34 54 65 34 12 09
3 41 54 33 61 71 12 09 08 08 12
How can I get the average of these where ID1 = 14.5, ID2 = 36.625 etc
I can't just do D1 + D2 + D3... / 10 as the 10 isn't always 10
The ideal would just be to do AVG(D1:D10) but clearly the world isn't ideal!
You can't use AVG aggregate function (because it works on rows) but you can calculate an average using the following query:
SELECT
(ISNULL(D1,0) + ISNULL(D2,0) +
ISNULL(D3,0) + ISNULL(D4,0) + ISNULL(D5,0) +
ISNULL(D6,0) + ISNULL(D7,0) + ISNULL(D8,0) +
ISNULL(D9,0) + ISNULL(D10,0)) /
CASE
WHEN
D1 IS NOT NULL
OR D2 IS NOT NULL
OR D3 IS NOT NULL
OR D4 IS NOT NULL
OR D5 IS NOT NULL
OR D6 IS NOT NULL
OR D7 IS NOT NULL
OR D8 IS NOT NULL
OR D9 IS NOT NULL
OR D10 IS NOT NULL
THEN
(
CASE
WHEN D1 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D2 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D3 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D4 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D5 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D6 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D7 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D8 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D9 IS NOT NULL THEN 1 ELSE 0
END +
CASE
WHEN D10 IS NOT NULL THEN 1 ELSE 0
END
)
ELSE 1
END
FROM yourtable
AVG for each id:
select id, avg(d) from
(
select id, id1 as d from tablename
union all
select id, id2 as d from tablename
union all
select id, id3 as d from tablename
union all
select id, id4 as d from tablename
union all
select id, id5 as d from tablename
union all
select id, id6 as d from tablename
union all
select id, id7 as d from tablename
union all
select id, id8 as d from tablename
union all
select id, id9 as d from tablename
union all
select id, id10 as d from tablename)
group by id
Use Values table valued constructor to unpivot the data then find average per ID. Try this
select id,avg(data) from Yourtable
cross apply
(values(D1), (D2), (D3), (D4), (D5), (D6) ,(D7), (D8), (D9) ,(D10)) cs (data)
group by id
Or if your want decimal values then use this.
select id,sum(data)/sum(case when data is not null then 1.0 else 0 end) from Yourtable
cross apply
(values(D1), (D2), (D3), (D4), (D5), (D6) ,(D7), (D8), (D9) ,(D10)) cs (data)
group by id

Conditional UNPIVOT in TSQL

Let's say I have a table with an ID column, and several property columns
MyTable (ID, PI, P2, P3, P4)
ID P1 P2 P3 P4
1 A1 B C1 D1
2 C1 C2 B NULL
3 C2 Z NULL NULL
4 X A1 C1 NULL
So, I need to write a query to find out how many distinct property values out there, no matter in which column they are.
Value Count
A1 2
B 2
C1 3
C2 2
X1 1
...
I think I can get this by using UNPIVOT (correct me, if I am wrong)
Now, how can I get similar count but grouped by a number of non-null values in the row (the count of non-null values per row may, or may not include key columns, doesn't matter), i.e. output like this:
Value NonNullCount Count
A1 3 1
A1 4 1
B 3 1
B 4 1
C1 2 3
C1 4 1
C2 3 1
C2 2 1
...
Here is one method, using cross apply for the unpivot:
select vals.p, t.NonNullCount, count(*)
from (select t.*,
((case when p1 is not null then 1 else 0 end) +
(case when p2 is not null then 1 else 0 end) +
(case when p3 is not null then 1 else 0 end) +
(case when p4 is not null then 1 else 0 end)
) as NonNullCount
from table t
) t cross apply
(values (p1), (p2), (p3), (p4)) vals(p)
where vals.p is not null
group by vals.p, t.NonNullCount;

sql query to find what is not in group three

i have one SQL Table in which some dummy data.
i want that dummy data and update that row with column type
my table tbl
ID D1 M1 C1 QTY TYPE
1 D1 M1 C1 1 Y
2 D1 M2 C1 2 Y
3 D1 M3 C1 3 Y
4 D1 M1 C1 1 Y
5 D2 M1 C1 1 Y
6 D2 M2 C1 2 Y
7 D2 M3 C2 3 Y
8 D2 M1 C1 1 Y
9 D2 M2 C1 2 Y
10 D3 M1 C1 1 Y
11 D3 M2 C1 2 Y
12 D3 M3 C1 3 Y
13 D3 M1 C1 1 Y
14 D3 M2 C1 2 Y
15 D3 M3 C1 3 Y
16 D3 M1 C2 1 Y
grouping on Column D1 and M1
I have a N no. of records, now I have to identify group of 3 record and if any record remain then it should be set as "No" else "yes"
Ex:
condition 1: If I have 4 records, then make a group of 3-3 records so remain last 1 record should be set an "no".
condition 2: If I have 5 records, then make a group of 3-3 records so remain last 2 records will be set as "No"
Condition 3: if I have 7 records, then make a group of 3-3 records so remain last 1 record will be set as "No"
my expected answer is as below
ID D1 M1 C1 QTY TYPE
1 D1 M1 C1 1 YES
2 D1 M2 C1 2 YES
3 D1 M3 C1 3 YES
4 D1 M1 C1 1 NO
5 D2 M1 C1 1 YES
6 D2 M2 C1 2 YES
7 D2 M3 C2 3 YES
8 D2 M1 C1 1 NO
9 D2 M2 C1 2 NO
10 D3 M1 C1 1 YES
11 D3 M2 C1 2 YES
12 D3 M3 C1 3 YES
13 D3 M1 C1 1 YES
14 D3 M2 C1 2 YES
15 D3 M3 C1 3 YES
16 D3 M1 C2 1 NO
SQLFIDDLE
Please tell me solution.
Is this what you are looking for?
with toupdate as (
select t.*, row_number() over (partition by d1 order by id) as seqnum,
count(*) over (partition by d1) as cnt
from tbl t
)
update toupdate
set type = (case when seqnum <= 3*(cnt /3) then 'yes' else 'no' end);
You can also run similar logic as a select:
select t.*, (case when seqnum <= 3*(cnt /3) then 'yes' else 'no' end)
from (
select t.*, row_number() over (partition by d1 order by id) as seqnum,
count(*) over (partition by d1) as cnt
from tbl t
) t;