Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 New to SQL Server Programming
 Query replace NULL value in a row with MAX value

Author  Topic 

potn1
Starting Member

33 Posts

Posted - 2011-05-17 : 00:29:46
I've got a query that is displaying specific months within a date range among other fields. There is a column called total_amount and for a specific month this number is 50. All of the other months have this total_amount as 0. Is there a way I can make all of these other amounts 50 as well? Basically something along the lines of ISNULL(total_amount,50) but I need it to be something that can be generated automatically because the number I am looking to duplicate won't always be 50.

Thanks in advance!

jackv
Master Smack Fu Yak Hacker

2179 Posts

Posted - 2011-05-17 : 01:20:53
You could use CASE expression - that allows manipulation of data. Are you able to post your query?

Jack Vamvas
--------------------
http://www.sqlserver-dba.com
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-17 : 09:57:37
SELECT person_id, MONTH(user_date), YEAR(user_date), total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date

Right now my query will display all rows within the specific range of dates. The total_amount for 1 of these months would be 50 and the rest would be 0. Basically I just would like a way where I could auto-fill the other rows when the total_amount is 0 to display as 50. These will differ between people so I cannot just use the ISNULL(total_amount,50). Thanks!

edit: Would there be a way to select the MAX value from the result and replace that value in my total_amount column for all rows?
Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-05-17 : 10:23:09
This is picking the max amount for each person_id within the date range you have specified
SELECT
person_id,
MONTH(user_date),
YEAR(user_date),
max(total_amount) OVER (PARTITION BY person_id)
FROM
person
WHERE
user_date >= @start_date
AND user_date <= @end_date
Go to Top of Page

phipywr
Starting Member

6 Posts

Posted - 2011-05-17 : 11:08:14
The method to adjust the value to 50 when zero would be like this:
SELECT person_id
, MONTH(user_date)
, YEAR(user_date)
, case when total_amount = 0
then 50
else total_amount
end as total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date


quote:
Originally posted by potn1

SELECT person_id, MONTH(user_date), YEAR(user_date), total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date

Right now my query will display all rows within the specific range of dates. The total_amount for 1 of these months would be 50 and the rest would be 0. Basically I just would like a way where I could auto-fill the other rows when the total_amount is 0 to display as 50. These will differ between people so I cannot just use the ISNULL(total_amount,50). Thanks!

edit: Would there be a way to select the MAX value from the result and replace that value in my total_amount column for all rows?



Have an ordinary day
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-17 : 11:20:38
quote:
Originally posted by sunitabeck

This is picking the max amount for each person_id within the date range you have specified
SELECT
person_id,
MONTH(user_date),
YEAR(user_date),
max(total_amount) OVER (PARTITION BY person_id)
FROM
person
WHERE
user_date >= @start_date
AND user_date <= @end_date



I tested this on person_id 18 who has 5 records (Jan,Feb,March,Apr,May) between the date range and it seems to be leaving the other values as 0. February is the only month where they have a total_amount of 50. January, March, April and May the total_amount is 0. I am trying to get those 4 other months to also display a total_amount of 50. Is what you posted supposed to work for what I'm looking for?

Thanks!
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-17 : 11:23:31
quote:
Originally posted by phipywr

The method to adjust the value to 50 when zero would be like this:
SELECT person_id
, MONTH(user_date)
, YEAR(user_date)
, case when total_amount = 0
then 50
else total_amount
end as total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date


quote:
Originally posted by potn1

SELECT person_id, MONTH(user_date), YEAR(user_date), total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date

Right now my query will display all rows within the specific range of dates. The total_amount for 1 of these months would be 50 and the rest would be 0. Basically I just would like a way where I could auto-fill the other rows when the total_amount is 0 to display as 50. These will differ between people so I cannot just use the ISNULL(total_amount,50). Thanks!

edit: Would there be a way to select the MAX value from the result and replace that value in my total_amount column for all rows?



Have an ordinary day


But the value will not always be 50 that I want displayed. It will be the MAX value of total_amount returned per each specific person_id. So replacing 0 with 50 would only work for this specific person.

Is there anyway to use a CASE when total_amount is 0 to replace that with the MAX total_amount from a dataset?
Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-05-17 : 12:40:45
quote:
Originally posted by potn1

quote:
Originally posted by sunitabeck

This is picking the max amount for each person_id within the date range you have specified
SELECT
person_id,
MONTH(user_date),
YEAR(user_date),
max(total_amount) OVER (PARTITION BY person_id)
FROM
person
WHERE
user_date >= @start_date
AND user_date <= @end_date



I tested this on person_id 18 who has 5 records (Jan,Feb,March,Apr,May) between the date range and it seems to be leaving the other values as 0. February is the only month where they have a total_amount of 50. January, March, April and May the total_amount is 0. I am trying to get those 4 other months to also display a total_amount of 50. Is what you posted supposed to work for what I'm looking for?

Thanks!

This is most likely because your @start_date and @end_date cover only February. The query is really looking within the date range you specified via those two variables, picking up the largest value, and assigning that value to all the rows WITHIN that date range.

If you want to ignore the date range while picking the value to be used, then you could do the following:

;WITH Totals AS
(
SELECT person_id, MAX(total_amount) AS TotalForUser GROUP BY person_id
)
SELECT
p.person_id,
MONTH(user_date),
YEAR(user_date),
TotalForUser
FROM
person p
INNER JOIN Totals t ON t.person_id = p.person_id
WHERE
user_date >= @start_date
AND user_date <= @end_date
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-17 : 14:07:20
Is Totals basically a temporary table that determines each person_id MAX total_amount and then you grab that data to display within your query?
Go to Top of Page

phipywr
Starting Member

6 Posts

Posted - 2011-05-17 : 14:43:59
In my example 50 would be used for any person who had 0 in the amount. To use the max amount, one way to do it would be to use a subselect. (Note I also cleaned up the where clause)

SELECT person_id
, MONTH(user_date)
, YEAR(user_date)
, case when total_amount = 0
then (select max(total_amount) from person)
else total_amount
end as total_amount
FROM person
WHERE user_date between @start_date and @end_date

If you have a lot of rows that are zero this could be a little slow, though.

If you are creating a stored procedure, you could set a variable to the max amount and then just use that variable in your case statement instead.


quote:
Originally posted by potn1

[quote]Originally posted by phipywr

The method to adjust the value to 50 when zero would be like this:
SELECT person_id
, MONTH(user_date)
, YEAR(user_date)
, case when total_amount = 0
then 50
else total_amount
end as total_amount
FROM person
WHERE user_date >= @start_date AND user_date <= @end_date


But the value will not always be 50 that I want displayed. It will be the MAX value of total_amount returned per each specific person_id. So replacing 0 with 50 would only work for this specific person.

Is there anyway to use a CASE when total_amount is 0 to replace that with the MAX total_amount from a dataset?



Have an ordinary day
Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-05-17 : 14:55:28
quote:
Originally posted by potn1

Is Totals basically a temporary table that determines each person_id MAX total_amount and then you grab that data to display within your query?


It is a CTE (common table expression), which conceptually you can think of as a temporary table or table variable - but there are some important differences.
Go to Top of Page

jimf
Master Smack Fu Yak Hacker

2875 Posts

Posted - 2011-05-17 : 14:58:05
Nice work!

Jim

Everyday I learn something that somebody else already knew
Go to Top of Page

phipywr
Starting Member

6 Posts

Posted - 2011-05-18 : 10:21:19
In our shop CTE's have invariably performed really poorly. My testing revealed that using table variables or temp tables (depending upon size of results) was always significantly faster. Any idea why?

quote:
Originally posted by sunitabeck

quote:
Originally posted by potn1

Is Totals basically a temporary table that determines each person_id MAX total_amount and then you grab that data to display within your query?


It is a CTE (common table expression), which conceptually you can think of as a temporary table or table variable - but there are some important differences.

Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-05-18 : 10:30:29
I have seen improved performance with temp tables in many cases, but not with table variables, especially when you add indexes to the temp tables. You cannot add indexes to CTE's or table variables.

I have seen improved performance with temp tables even without indexes sometimes - my guess is that that is because when you use temp tables, each individual transaction is smaller, involving fewer tables - but I am speculating.
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-23 : 14:24:15
Right now this query will display a row for every month within the date range. Only one of these rows will have data in every column. Basically if I select a range of 9 months, person_id of 18 will only show up in the row with data. The other 8 rows will show NULL for the person_id column. Is there a way I can get the person_id of 18 to show up in every other row of this query? I think a TOP 1 needs to be used but when I try to do that in my initial select statement it says that the PersonInfo table does not exist. Are you not able to select the top value from a subquery? Thanks

SELECT PersonInfo.person_id, Calendar.MNumber, Calendar_Year.MName,Calendar_Year.Year,total_amount
FROM (select distinct MNumber, MName from Calendar_Year) Calendar
LEFT JOIN (SELECT person_id, MNumber, MName, Year,
ISNULL(total_amount,0) as total_amount,
FROM person p
WHERE user_date >= @start_date AND user_date <= @end_date
AND person_id = 19) AS PersonInfo
ON Calendar.MNumber = PersonInfo.MNumber
LEFT JOIN Calendar_Year ON Calendar_Year.MNumber = Calendar.MNumber
Go to Top of Page

potn1
Starting Member

33 Posts

Posted - 2011-05-24 : 10:31:49
Any ideas? When I try to SELECT values from PersonInfo it says the table does not exist, is there anyway to SELECT a top value from a subquery?
Go to Top of Page
   

- Advertisement -