I'm currently working with writing database procedures for HANA via ABAP objects. I'd like to return a scalar value which is calculated from a selection rather than a table which the other developer would have to read from a table. I'd prefer that I'm not declaring variables to use in the store procedure through the importing/exporting parameters.
methods: _amdp_previous_years
importing value(mandt) type mandt
value(in_object) type j_objnr
value(in_year) type gjahr
exporting value(out_results) type total_table
value(out_total) type f.
method _amdp_previous_years by database procedure for hdb
language sqlscript options read-only
using rpsco.
declare totals double array;
declare out_array double array;
-- begin of totals,
-- total type float,
-- end of totals,
-- out_results = type table of totals
out_results = select sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) as total from rpsco
where objnr = :in_object
and gjahr = :in_year;
totals := array_agg( :out_results.total );
out_total := :totals[1];
-- Type not declared
-- in sap = wlp01 = curr(15,2)
-- total is not a decimal
-- total is not a double
-- total is not a float
-- total is not a int
-- total is not a real
-- what is total supposed to be then?
results = select sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) as total from rpsco
where objnr = :in_object
and gjahr = :in_year;
out_array := array_agg( :results.total );
endmethod.
The first statement works ok, I'm guessing because the result of the selection gets placed into a field that is declared as an ABAP float.
The second selection works and results is populated, however I'm not sure how to access the columns. The SAP data element is a CURRENCY field (15,2). I've tried all of the scalar types in the documentation. I received the same error that it is not the correct type.
Is this not possible because the type isn't explicitly defined before hand? While looking around the internet at tutorials people suggest using CREATE TYPE or CREATE TABLE, but I receive syntax errors when trying to use these statements.
I can answer this myself in case anybody else stumbles upon this. You can typecast the columns via various functions such as to_double( ), to_integer( ), and so forth. Now the selection looks like:
results = select to_double( sum( wlp01 ) + sum( wlp02 ) + sum( wlp03 ) + sum( wlp04 ) + sum( wlp05 ) +
sum( wlp06 ) + sum( wlp07 ) + sum( wlp08 ) + sum( wlp09 ) + sum( wlp10 ) +
sum( wlp11 ) + sum( wlp12 ) + sum( wlp13 ) + sum( wlp14 ) + sum( wlp15 ) +
sum( wlp16 ) ) as total from rpsco
where objnr = :in_object
and gjahr < :in_year;
Related
I'm trying to test some codes in SQL, in this case one being to calculate the Amount Due.
Our database has a field that calculates it through this expression:
round(total_amount - if( isNull( amount_paid ), 0, amount_paid )
- if( isNull( terms_taken ), 0, terms_taken )
- if( isNull( tax_terms_taken ), 0, tax_terms_taken )
- if( isNull( allowed ), 0, allowed )
+ if( isNull( memo_amount ), 0, memo_amount )
+ if( isNull( bad_debt_amount ), 0, bad_debt_amount ),
2)
However when I try to use Excel to query this from the database, it states that the isNull function requires 2 arguments.
What would be the best way to achieve this?
Excel isNULL expects single argument where as SQL ISNULL expects
two arguments.
What you have shown us is EXCEL query. But won't
work in SQL. In SQL, you will need to replace if(isnull(..), , ) with isnull(..., VALUE_THAT_YOU_WANT_TO_USE_WHEN_IT_IS_NULL). So your SQL equivalent query is:
round(total_amount
- isNull( amount_paid, 0)
- isNull( terms_taken, 0 )
- isNull( tax_terms_taken, 0)
- isNull( allowed, 0 )
+ isNull( memo_amount, 0)
+ isNull( bad_debt_amount, 0 )
, 2)
I have a table which I need to pivot for reporting services:
DateCreated Rands Units Average Price Success % Unique Users
-------------------------------------------------------------------------
2013-08-26 0 0 0 0 0
2013-08-27 0 0 0 0 0
2013-08-28 10 2 5 100 1
2013-08-29 12 1 12 100 1
2013-08-30 71 9 8 100 1
2013-08-31 0 0 0 0 0
2013-09-01 0 0 0 0 0
In other words I need to have Rands, Units, Average Price etc at rows and the dates as columns.
I have read various examples but I just can't seem to get it right.
Any help would be much appreciated!
This one will do what you want, but you have to specify all the dates
select
c.Name,
max(case when t.DateCreated = '2013-08-26' then c.Value end) as [2013-08-26],
max(case when t.DateCreated = '2013-08-27' then c.Value end) as [2013-08-27],
max(case when t.DateCreated = '2013-08-28' then c.Value end) as [2013-08-28],
max(case when t.DateCreated = '2013-08-29' then c.Value end) as [2013-08-29],
max(case when t.DateCreated = '2013-08-30' then c.Value end) as [2013-08-30],
max(case when t.DateCreated = '2013-08-31' then c.Value end) as [2013-08-31],
max(case when t.DateCreated = '2013-09-01' then c.Value end) as [2013-09-01]
from test as t
outer apply (
select 'Rands', Rands union all
select 'Units', Units union all
select 'Average Price', [Average Price] union all
select 'Success %', [Success %] union all
select 'Unique Users', [Unique Users]
) as C(Name, Value)
group by c.Name
You can create a dynamic SQL for this, something like this:
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ',', '') +
'max(case when t.DateCreated = ''' + convert(nvarchar(8), t.DateCreated, 112) + ''' then c.Value end) as [' + convert(nvarchar(8), t.DateCreated, 112) + ']'
from test as t
select #stmt = '
select
c.Name, ' + #stmt + ' from test as t
outer apply (
select ''Rands'', Rands union all
select ''Units'', Units union all
select ''Average Price'', [Average Price] union all
select ''Success %'', [Success %] union all
select ''Unique Users'', [Unique Users]
) as C(Name, Value)
group by c.Name'
exec sp_executesql #stmt = #stmt
I solved this in the end using dynamic sql, very similar to the marked answer. I wasn't able to find a way of doing this without dynamic sql. The dates had to be in order and the last 7 days, they also had to use the day of the week names (which I didn't specify in the question).
The biggest change I needed to make was changing the table variable into a temporary table.
This is because dynamic sql statements execute in a different context and don't know about any variables you have created.
In the end I was completely off track trying to use PIVOT and APPLY should be used in situations where there are more than one "type" of value.
I have included my solution below since it could help someone who has a similar problem:
CREATE TABLE #SummaryTable
(
[DateCreated] DATE UNIQUE,
[Rands] DECIMAL,
[Units] INT,
[Average Price] DECIMAL,
[Success %] INT,
[Unique Users] INT
);
--Code to fill table
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ',', '') +
'max(case when t.DateCreated = ''' + convert(nvarchar(16), t.DateCreated, 126)
+ ''' then c.Value end) as [' + left(datename(dw, t.DateCreated),3) + ']'
from #SummaryTable as t
select #stmt = '
select
c.Name, ' + #stmt + ' from #SummaryTable as t
outer apply (
select ''Rands'', Rands union all
select ''Units'', Units union all
select ''Average Price'', [Average Price] union all
select ''Success'', [Success %] union all
select ''Unique Users'', [Unique Users]
) as C(Name, Value)
group by c.Name'
exec(#stmt)
I am trying to cap particular fields so that they don't exceed a particular value.
For example, something like this would suffice, where I can specify that a field should not exceed 8:
SELECT (
cap(t.MondayHrs,8)
+ cap(t.TuesdayHrs,8)
+ cap(t.WednesdayHrs,8)
+ cap(t.ThursdayHrs,8)
+ cap(t.FridayHrs,8)
) as TotalHours
If MondayHrs = 7, then it should be added to TotalHours as 7.
If MondayHrs = 10, then it should be added to TotalHours as 8 (my capped value)
Is there anything built into T-SQL that could facilitate this?
create function Cap (#Value float,#maxValue float) Returns float
as
begin
Declare #Result float
if #Value > #maxValue select #Result=#Maxvalue else select #Result=#Value
Return #Result
end;
usage
Select dbo.Cap(1,10),dbo.Cap(11,10)
Try...
select least(t.MondayHrs,8)
+ least(t.TuesdayHrs,8)
+ least(t.WednesdayHrs,8)
+ least(t.ThursdayHrs,8)
+ least(t.FridayHrs,8)
) as TotalHours
An alternate idea would be to use CASE. For example:
SELECT (
(CASE WHEN t.MondayHrs > 8 THEN 8 ELSE t.MondayHrs END)
+ (CASE WHEN t.TuesdayHrs > 8 THEN 8 ELSE t.TuesdayHrs END)
) as TotalHours
You can write a function for that like MySQL GREATEST.
Then you could do something like
select greatest(some_col, 8) +
greatest(other_col, 8) +
...
from your_table
I have the following query:
SELECT CAST(year_week AS NUMERIC) as year_week FROM web_details where location = ''JF'' AND property_id = ''FARM''
which produces the following results.
YEAR_WEEK
201035
201036
201037
201039
201041
201044
201045
201048
What I actually want is to produce a set of results which only displays values if the consecutive value is available - so producing the following results...
YEAR_WEEK
201035
201036
201044
To add another spanner into the works, the column year_week is not a numeric value so has needed to be converted.
Thanks
SELECT
CAST(year_week AS NUMERIC) as year_week
FROM
web_details wd
WHERE
EXISTS(
SELECT
year_week
FROM
web_details wd2
WHERE
wd2.year_week = CASE(RIGHT(wd.year_week, 2))
WHEN '48' THEN CAST((CAST(LEFT(wd.year_week,4) AS INT) + 1) AS VARCHAR(4)) + '01'
ELSE LEFT(wd.year_week,4) + CAST((CAST(RIGHT(wd.year_week,2) AS INT) + 1) AS VARCHAR(2))
END
)
Basically, my approach is that you calculate another column that contains the next year_week value, and the join it to itself.
WITH myCTE AS (
SELECT year_week, CONVERT(VARCHAR(4),DATEPART(year,CONVERT(datetime,LEFT(year_week,4)) + (RIGHT(year_week,2) + 1) * 7 )) + RIGHT( '000' + CONVERT(VARCHAR(2),DATEPART(MONTH,CONVERT(datetime,LEFT(year_week,4)) + (RIGHT(year_week,2) + 1) * 7)),2) next_year_week
FROM web_details
WHERE ..........
)
SELECT T1.year_week, T2.year_week
FROM myCTE T1
INNER JOIN myCTE T2 ON T1.next_year_week = T2.year_week
I have a database in the following format:
ID TYPE SUBTYPE COUNT MONTH
1 A Z 1 7/1/2008
1 A Z 3 7/1/2008
2 B C 2 7/2/2008
1 A Z 3 7/2/2008
Can I use SQL to convert it into this:
ID A_Z B_C MONTH
1 4 0 7/1/2008
2 0 2 7/2/2008
1 0 3 7/2/2008
So, the TYPE, SUBTYPE are concatenated into new columns and COUNT is summed where the ID and MONTH match.
Any tips would be appreciated. Is this possible in SQL or should I program it manually?
The database is SQL Server 2005.
Assume there are 100s of TYPES and SUBTYPES so and 'A' and 'Z' shouldn't be hard coded but generated dynamically.
SQL Server 2005 offers a very useful PIVOT and UNPIVOT operator which allow you to make this code maintenance-free using PIVOT and some code generation/dynamic SQL
/*
CREATE TABLE [dbo].[stackoverflow_159456](
[ID] [int] NOT NULL,
[TYPE] [char](1) NOT NULL,
[SUBTYPE] [char](1) NOT NULL,
[COUNT] [int] NOT NULL,
[MONTH] [datetime] NOT NULL
) ON [PRIMARY]
*/
DECLARE #sql AS varchar(max)
DECLARE #pivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #select_list AS varchar(max) -- Leave NULL for COALESCE technique
SELECT #pivot_list = COALESCE(#pivot_list + ', ', '') + '[' + PIVOT_CODE + ']'
,#select_list = COALESCE(#select_list + ', ', '') + 'ISNULL([' + PIVOT_CODE + '], 0) AS [' + PIVOT_CODE + ']'
FROM (
SELECT DISTINCT [TYPE] + '_' + SUBTYPE AS PIVOT_CODE
FROM stackoverflow_159456
) AS PIVOT_CODES
SET #sql = '
;WITH p AS (
SELECT ID, [MONTH], [TYPE] + ''_'' + SUBTYPE AS PIVOT_CODE, SUM([COUNT]) AS [COUNT]
FROM stackoverflow_159456
GROUP BY ID, [MONTH], [TYPE] + ''_'' + SUBTYPE
)
SELECT ID, [MONTH], ' + #select_list + '
FROM p
PIVOT (
SUM([COUNT])
FOR PIVOT_CODE IN (
' + #pivot_list + '
)
) AS pvt
'
EXEC (#sql)
select id,
sum(case when type = 'A' and subtype = 'Z' then [count] else 0 end) as A_Z,
sum(case when type = 'B' and subtype = 'C' then [count] else 0 end) as B_C,
month
from tbl_why_would_u_do_this
group by id, month
You change requirements more than our marketing team! If you want it to be dynamic you'll need to fall back on a sproc.