T-SQL - having arithmetic deficiency syndrome - sql

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.

Related

Row wise and conditions average in 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;

Looking for an alternative SQL statement

Given the following table with 2 columns:
c1 c2
------------
a1 | b1
a1 | b1
a2 | b2
a2 | b3
a3 | b3
I want to return those values from column c2 where the value of c2 column appears multiple times for the same c1 value. I am doing the following SQL query to return the required result:
SELECT DISTINCT ( c2 ) AS c
FROM ( SELECT c1 , c2 , COUNT (*) AS rowcount
FROM table
GROUP BY c1 , c2 HAVING rowcount > 1 )
Result:
c
---
b1
Is there any alternative SQL statement of the above query?
Based on your description, you can use:
select distinct c1
from (select t.*, count(*) over (partition by c2) as cnt
from t
) t
where cnt >= 2;
Based on your sample results:
select c1
from t
group by c1
having count(*) >= 2;
And based on the revised question:
select c2
from t
group by c2
having count(*) >= 2;
Use count in having clause instead of using subquery:-
select c1
from table
group by c1
having count(c2) > 1
Most answers above will work if you want all the values in c1 that appear more than once in the table (even with the same value on c2).
If you want to measure only values of c1 that may have multiple DISTINCT values on c2 you can use:
SELECT c1
FROM table
GROUP BY c1
HAVING COUNT(DISTINCT c2) > 1

How can this stored procedure be more elegant using unpivot

The data I have is in the following format:
ID Category Gender Cost
1 C1 M 40
2 C2 F 50
3 C3 M 60
4 C1 F 40
5 C3 M 70
6 C3 F 50
.
.
.
and so on
Only C1, C2 and C3 exist as categories
The result I need is:
Category Male % Female % Avg. Cost
C1 0.5 0.5 40
C2 0 1 50
C3 0.6 0.4 60
What I have done in the stored procedure is I declared variables for C1 count, C2 count and C3 count, C1 female count, C2 female count, C3 female count, C1 Total Cost, C2 Total Cost, C3 Total cost, you get the idea. Then I calculated the average cost and male / female percentages.
It works but it's not a very elegant solution. I couldn't get the unpivot query to work so it gives me the result I need. Can this be done using unpivot or am I misunderstanding how pivots work? I tried something like this below but couldn't figure out how to include M/F percentage and average cost per category.
Thanks.
Something like this (which is incomplete):
Declare #TotalCount int;
SELECT #TotalCount = count(*) from MyTable;
SELECT Category, p.Total, CAST(p.Total * 1.0 / #TotalCount AS float) AS Percentage FROM --How to get F or M percentage, Average Cost Per Category , etc?
(
SELECT ISNULL(SUM(c.C1), 0) AS C1,
ISNULL(SUM(c.C2), 0) AS C2,
ISNULL(SUM(c.C3), 0) AS C3
FROM
(SELECT CASE WHEN Category = 'C1' THEN 1 ELSE 0 END AS C1,
CASE WHEN Category = 'C2' THEN 1 ELSE 0 END AS C2,
CASE WHEN Category = 'C3' THEN 1 ELSE 0 END AS C3
FROM #Candidates
) c --Do I need
) a
UNPIVOT
(
Total FOR Suitability IN (
C1,
C2,
C3
)
) p
Please check below query:
select
Category,
CAST(1.00*sum(case when Gender='M' then 1 else 0 end)/COUNT(Category) AS NUMERIC(18,1)) [Male %],
CAST(1.00*sum(case when Gender='F' then 1 else 0 end)/COUNT(Category) AS NUMERIC(18,1)) [Female %],
AVG(Cost) [Avg. Cost]
from tbl
group by Category
SQL Fiddle Demo

Query to update row which contains maximum column value in MS SQL 2008

I have a table similar to below:
C1 C2 C3
A 5 0
A 15 0
A 2 0
B 5 0
B 8 0
Result table updates C3 with 1 for mac value of C2 group by C1
C1 C2 C3
A 5 0
A 15 1
A 2 0
B 5 0
B 8 1
For SQL Server 2005+:
;WITH CTE AS
(
SELECT *,
MAX(C2) OVER(PARTITION BY C1) MaxC2
FROM YourTable
)
UPDATE CTE
SET C3 = CASE WHEN MaxC2 = C2 THEN 1 ELSE 0 END
Supossing table is named table_name
UPDATE t1 SET t1.C3 = 1
FROM table_name as t1 INNER JOIN (
SELECT C1, MAX(C2) AS C2 FROM table_name GROUP BY C1
) AS t2 ON t1.C1 = t2.C1 AND t1.C2 = t2.C2

SQL Return Null if One Column is Null (Opposite of COALESCE())

In advance, I would like to say thanks for the help. This is a great community and I've found many programming answers here.
I have a table with multiple columns, 5 of which contain dates or null.
I would like to write an sql query that essentially coalesces the 5 columns into 1 column, with the condition that if 1 of the five columns contains a "NULL" value, the returned value is null. Essentially the opposite of the coalesce condition of returning the first non-null, I want to return the first null. If none are null, returning the greatest of the 5 dates would be optimal, however I can settle with returning any one of the 5 dates.
C1 C2 C3 C4 C5
-- -- -- -- --
1/1/1991 1/1/1991 1/1/1991 1/1/1991 2/2/1992
NULL 1/1/1991 1/1/1991 1/1/1991 1/1/1991
Query Returns:
C1
--
2/2/1992
NULL
Thank you very much.
(Server is MSSQL2008)
select greatest(c1, c2, c3, c4, c5)
from table;
Life can be so easy :-)
(edit: works on Oracle)
Without overthinking it:
SELECT
CASE WHEN c1 is null or c2 is null or c3 is null or c4 is null or c5 is null
THEN null
ELSE c1
END
FROM mytable
My edit is as follows:
CASE
WHEN (c1 >= c2 AND c1 >= c3) THEN c1
WHEN (c2 >= c1 AND c2 >= c3) THEN c2
WHEN (c3 >= c1 AND c3 >= c2) THEN c3
END
Try this:
SELECT
CASE WHEN t1.SomeDate IS NULL THEN NULL ELSE MAX(t1.SomeDate) END AS TheVal
FROM
(
SELECT C1 AS SomeDate FROM Table_1
UNION ALL
SELECT C2 AS SomeDate FROM Table_1
UNION ALL
SELECT C3 AS SomeDate FROM Table_1
UNION ALL
SELECT C4 AS SomeDate FROM Table_1
UNION ALL
SELECT C5 AS SomeDate FROM Table_1
) t1
GROUP BY
t1.SomeDate
perhaps a variation on coalesce (replace -1 with an invalid value)?
SELECT CASE WHEN COALESCE(C1,C2,C3,C4,C5,-1) = -1 THEN NULL ELSE COALESCE(C1,C2,C3,C4,C5) END
Maybe with LEAST?
I don't know how this works with NULL.
SELECT
CASE WHEN C1 IS NULL THEN C2 WHEN C1 IS NULL AND C2 IS NULL THEN C3 WHEN C1 IS NULL AND C2 IS NULL AND C3 IS NULL THEN C4 WHEN C1 IS NULL AND C2 IS NULL AND C3 IS NULL AND C4 IS NULL THEN C5 ELSE C1 END AS REQUIREDNOTNULLVALUE
FROM
TABLE1