Update the sum value in second row - sql

I have table like followed by
User Col1 Col2
ABC 35 75
ABC 500 75
and I need the select query for following output.
User Col1 Col2 Result
ABC 35 75 40
ABC 500 75 115
Check col1<col2 then Result Col2-Col1
else
Col2 + Result(Row1)
Ex:
35<75 then 40
else
75+40
I don't know how to start please help us for output..
Thanks in advance
What I have tried
Select User,Col1,Col2
,Case When Col1<Col2 then Col2-Col1 Else Col2 End as Result
Then i got the output like followed by
User Col1 Col2 Result
ABC 35 75 40
ABC 500 75 **75**
I need 115 instead of 75 in Result of second row

CREATE TABLE #tmp
(
UserName VARCHAR(10),
col1 INT,
col2 INT
)
INSERT INTO #tmp (UserName, col1, col2)
SELECT 'ABC', 35, 75
UNION ALL SELECT 'ABC', 500, 75
SELECT tmp.UserName
,tmp.col1
,tmp.col2
,CASE WHEN tmp.Result = 0 THEN tmp.col2 + LAG(tmp.Result) OVER (ORDER BY (SELECT NULL)) ELSE tmp.Result END AS Result
FROM
(
Select UserName,Col1,Col2
,Case When Col1<Col2 then Col2-Col1 Else 0 End as Result
FROM #tmp
)tmp

You could try something like this:
SELECT *
,Case When Col1 < Col2 then Col2-Col1
Else (Col2 + LAG(Col2-Col1 ,1) OVER(ORDER BY Col2)) --Order by
End as Result
FROM TableName
By using LAG you can access the previous row of data. Then all I do is add the previous result to the Col2 value.
Else (Col2 + LAG(Col2-Col1 ,1) OVER(ORDER BY Col2))
Important note below.
The only thing to note here is the ORDER BY Col2. At the moment that will work for just the two rows of data. But, if you have more you should add some sort of auto incrementing ID field to keep the order the same as how you enter the data. Then you would change it to ORDER BY ID.

You can try below using lag() function
Select User,Col1,Col2
,Case When Col1<Col2 then Col2-Col1
Else Col2+lag(col2-col1) over(partition by user order by col2 ) End as Result
from tablename

You need to use the LAG function for this.here is the code...if you like the answer please vote.
Select *
,Case When Col1<Col2 then Col2-Col1
Else Col2+lag(col2-col1) over(partition by user order by col2 ) End as Result
from review

First, you need a column that represents the ordering of the rows.
If I generalize the problem, then you need the groups defined by col1 < col2. You can define the groups by taking a cumulative sum of when col1 < col2.
The actual calculation is then a cumulative sum over the group:
select t.*,
(case when col1 < col2 then col2 - col1
else sum(case when col1 > col2 then col2 - col1 else col2 end) over (partition by user, grp order by ?)
end) as result
from (select t.*,
sum(case when col1 < col2 then 1 else 0 end) over (partition by user order by ?) as grp
from t
) t
from t;
The ? is for the column that specifies the ordering of the rows.

Related

How to find count of multiple columns in sql group by id?

I have a table with schema like below:
root
|id
|name
|col1
|col2
|...
|col30
Conditions are that multiple rows can have the same name (they're not primary key - the key is the ID). Values in col1-col30 will be some string, or it can have the string "null".
I'm interested in the number of columns filled in for each name.
For example,
if name "test1" has col1-5 filled in a row, and another row has "test1" and have col1, 3, 10, 6 filled in (and the rest of unfilled columns are just string value "null"), "test1" should have value 9.
I'm pretty new to SQL and have been looking this up.. Please help.
Give this a try:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(col1) AS col1_max, -- Non-NULL values come before NULL
MAX(col2) AS col2_max
FROM MyTable
GROUP BY name
) src
You can add more the rest of the columns to fit your case.
Updated
I just realized your NULL case is with a "null" string. Modified:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(CASE WHEN col1 = 'null' THEN NULL ELSE col1 END) AS col1_max, -- Non-NULL values come before NULL
MAX(CASE WHEN col2 = 'null' THEN NULL ELSE col2 END) AS col2_max
FROM MyTable
GROUP BY name
) src
First you unpivot your table and count those rows that have not null values. In postgres, you can achieve this with unnest. I have only used col1..7 -- change to upto col30 in your case
WITH t AS(
SELECT id,name,
unnest(array['col1', 'col2', 'col3', 'col4', 'col5', 'col6', 'col7']) AS colname,
unnest(array[col1, col2, col3, col4, col5, col6, col7]) AS colvalue
FROM your_table)
SELECT id, name,
SUM(CASE WHEN colvalue IS NULL THEN 0 ELSE 1 END) AS count_filled
FROM t
GROUP BY 1,2;

How to do countIf() in Oracle

How do I select a variable which gives an output the same as the excel function:
COUNTIFS(A1:D1,"<25", A1:D1, ">16")?
I.e. to count the number of times the values in my four fields are between 16 and 25.
You can do this with count() and case expressions. Note: case has an optional else clause; if it is not used, then the default else "value" is null. Count only counts non-null values, so you can combine these observations to write compact code. WHAT is counted doesn't matter; so the case expression may return a number (1 is usual, but 0 is just as valid and will give the same result, since the values are COUNTED, not SUMMED) - but you could also have a string like 'x' or a date in the case expression. Just to illustrate that, I will use a string.
select count( case when col > 16 and col < 25 then 'x' end ) as ct from your_table;
Here your_table is the name of your table, col is the name of the column containing the values, and ct is the name of the resulting column (the label for the count of values that satisfy your condition).
Of course, in a database you can get the same result more easily:
select count(*) as ct from your_table where col > 16 and col < 25;
Note, though, that the values are in one column.
If instead you have a table with four COLUMNS and many rows, and all the values in all columns are numbers, and you want to add a column showing how many values are strictly between 16 and 25 IN EACH ROW, the solution is different (but it uses the same ideas):
select col1, col2, col3, col4,
case when col1 > 16 and col1 < 25 then 1 else 0 end +
case when col2 > 16 and col2 < 25 then 1 else 0 end +
case when col3 > 16 and col3 < 25 then 1 else 0 end +
case when col4 > 16 and col4 < 25 then 1 else 0 end as ct
from my_table;
You would do this in a SQL query using case:
select sum(case when col between 16 and 25 then 1 else 0 end)
from t;
Note that between is inclusive in SQL, not exclusive, so based on your code logic:
select sum(case when col > 16 and col < 25 then 1 else 0 end)
from t;
Think, you have a 'user_table', where some of the user's 'status' are active (code-11) and others are inactive (code-22). You can count active and inactive with this sql below.
select count(case when status = 11 then 1 end) u_active, count(case when status = 22 then 1 end) u_inactive, from user_table;

SQL: Select the minimum value from multiple columns with null values

I have a table like this one
ID Col1 Col2 Col3
-- ---- ---- ----
1 7 NULL 12
2 2 46 NULL
3 NULL NULL NULL
4 245 1 792
I wanted a query that yields the following result
ID Col1 Col2 Col3 MIN
-- ---- ---- ---- ---
1 7 NULL 12 7
2 2 46 NULL 2
3 NULL NULL NULL NULL
4 245 1 792 1
I mean, I wanted a column containing the minimum values out of Col1, Col2, and Col 3 for each row ignoring NULL values. In a previous question (What's the best way to select the minimum value from multiple columns?) there is an answer for non NULL values. I need a query as efficient as possible for a huge table.
Select Id,
Case When Col1 < Col2 And Col1 < Col3 Then Col1
When Col2 < Col1 And Col2 < Col3 Then Col2
Else Col3
End As MIN
From YourTableNameHere
Assuming you can define some "max" value (I'll use 9999 here) that your real values will never exceed:
Select Id,
Case When Col1 < COALESCE(Col2, 9999)
And Col1 < COALESCE(Col3, 9999) Then Col1
When Col2 < COALESCE(Col1, 9999)
And Col2 < COALESCE(Col3, 9999) Then Col2
Else Col3
End As MIN
From YourTableNameHere;
You didn't specify which version of Teradata you're using. If you're using version 14+ then you can use least.
Unfortunately least will return null if any of its arguments are null. From the docs:
LEAST supports 1-10 numeric values.
If numeric_value is the data type of the first argument, the return
data type is numeric. The remaining arguments in the input list must
be the same or compatible types. If either input parameter is NULL,
NULL is returned.
But you can get around that by using coalesce as Joe did in his answer.
select id,
least(coalesce(col1,9999),coalesce(col2,9999),coalesce(col3,9999))
from mytable
This might work:
Select id, Col1, Col2, Col3, least(Col1, Col2, Col3) as MIN From YourTableNameHere
in this way you don't need to check for nulls, just use min and a subquery
select tbl.id,tbl.col1,tbl.col2,tbl.col3,
(select min(t.col)
from (
select col1 as col from tbl_name t where t.id=tbl.id
union all
select col2 as col from tbl_name t where t.id=tbl.id
union all
select col3 as col from tbl_name t where t.id=tbl.id
)t)
from tbl_name tbl
Output:
1 7 NULL 12 7
2 2 46 NULL 2
3 NULL NULL NULL NULL
4 245 1 792 1
Just modify your query with coalesce():
Select Id,
(Case When Col1 <= coalesce(Col2, col3, col1) And
Col1 <= coalesce(Col3, col2, col1)
Then Col1
When Col2 <= coalesce(Col1, col3, col2) And
Col2 <= coalesce(Col3, col1, col2)
Then Col2
Else Col3
End) As MIN
From YourTableNameHere;
This doesn't require inventing a "magic" number or over-complicating the logic.
I found this solution to be more efficient than using multiple case statement clauses, which can get extremely lengthy when evaluating data from several columns across one row.
Also, I can't take credit for this solution as I found it on some website a year or so ago. Today I needed a refresh on this logic, and I couldn't find it anywhere. I found my old code and decided to share it in this forum now.
Creating your test table:
create table #testTable(ID int, Col1 int, Col2 int, Col3 int)
Insert into #testTable values(1,7,null,12)
Insert into #testTable values(2,2,46,null)
Insert into #testTable values(3,null,null,null)
Insert into #testTable values(4,245,1,792)
Finding min value in row data:
Select ID, Col1, Col2, Col3 ,(SELECT Min(v) FROM ( VALUES (Col1), (Col2), (Col3) ) AS value(v)) [MIN] from #testTable order by ID

SQL Server Select a row for where a column value does not exists

I have a table as
COl1____COL2____COL3
1_________1_____val1
1_________2_____val2
1_________3_____val3
2_________1_____val1
2_________2_____val2
2_________3_____val3
3_________1_____val1
3_________2_____val2
3_________4_____val4
No I want to have unique values from COL1 such that it should only show me COL1 value that does not have a value "3" under COL2
i.e. I want a query to return me
Result
3
Any help is much appreciated
SELECT col1
FROM YourTable
EXCEPT
SELECT col1
FROM YourTable
WHERE col2 = 3
Or
SELECT col1
FROM YourTable
GROUP BY col1
HAVING MAX(CASE
WHEN Col2 = 3 THEN 1
ELSE 0
END) = 0
select col1
from Tab
where col1 not in (select col1 from tab where col2 = 3)

SQL Selecting MIN value from row data with null values

My table in Oracle is like this
Col Col1 Col2 Col3 ColR
-- ---- ---- ---- ----
30 73 40 null -10
60 32 null 20 40
90 80 null null 10
80 45 81 30 50
I can also set 0 instead of null in the above column.
I need to find the min value from Col1,Col2,Col3 ignoring null or 0 and populate the ColR by subtracting from Col.
EDIT:
i wrote a CASE statement which doesn't work due to the null values inside my table.
SELECT col,col1,col2,col3,
CASE
WHEN Col1 < Col2 AND Col1 < Col3
THEN Col - Col1
WHEN Col2 < Col1 AND Col2 < Col3
THEN Col - Col2
ELSE Col - Col3
END ColR
FROM
(SELECT col,col1,
CASE
WHEN col22 IS NULL
THEN NULL( i can also SET TO 0 but it will mess WITH my other calculation TO find MIN)
ELSE ROUND( 100* ( (col22) / (col44)))
END col2 ,
CASE
WHEN col33 IS NULL
THEN NULL
ELSE ROUND( 100* ( (col33) / (col44)))
END col3
FROM TABLE
)
I have just included the case statement inside my select query. all the the column values all populated from another query.
It sounds like you want something like
SELECT least( (case when col1 is null or col1 = 0 then 999999999 else col1 end),
(case when col2 is null or col2 = 0 then 999999999 else col2 end),
(case when col3 is null or col3 = 0 then 999999999 else col3 end) )
FROM <<table name>>
where 999999999 is some numeric value that is large enough that it will always be larger than any other valid value. If it is possible that all three columns will have NULL or 0 values, then you'd probably want to add an additional check that if the result of that least function is 999999999 that you return 0 or NULL or whatever else makes sense.
#X-Zero was kind enough to put together a working SQL Fiddle example of this construct. Note that his example is filtering out the rows where all three columns have either NULL or 0 values.
// IF YOU NEED MINIMAL FROM COL1 or COL (ANY COLUMN)
SELECT MIN (COL1) FROM (SELECT * FROM TABLE WHERE COL1 IS NOT NULL)
Can you please elaborate I am not able to help you with this small set of info actually.
Oracle NVL Usage:
nvl(check_expression, replacement_value)
So
nvl(col2,0) ought to take of nulls that mess with your math.
So try:
CASE
WHEN nvl(col1,0) < nvl(col2,0) AND nvl(col1,0) < nvl(col3,0)
THEN Col - nvl(col1,0)
WHEN nvl(col2,0) < nvl(col1,0) AND nvl(col2,0) < nvl(col3,0)
THEN Col - nvl(col2,0)
ELSE Col - nvl(col3,0)
END ColR
EDIT: Taking X-Zero's point which I missed. I think if you replace the NULLS with 9999999 instead of 0, the logic will work, although that may be too specific to this sample data and not a real world solution.
If you want to ignore nulls in a column, you could wrap them with the NVL function. This replaces null values in a column with the value specified, for which you could use some large number. For example:
NVL(col1,99999)
Oracle Database SQL Reference - NVL: http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions105.htm