Subtract Group Columns in Matrix table in SSRS - matrix

I have a matrix table grouped by WBS and Acc at row level.
Then i have a column group "Table" with Plan & Actuals. What i want to get is (Plan)-(Actuals)
I used the below expression in a outer group column
=SUM(IIF(Fields!Table.Value = "Plan", (Fields!Total.Value),0))-SUM(IIF(Fields!Table.Value = "Actuals", (Fields!Total.Value),0))
The total.value is the total of plan and actuals individually.
I am getting an error in the calculated column (Expression)
The Matrix TableThe Matrix Table
The Dataset and Outputs (expected and current)

If you only ever have two fixed values in your Table column then you should be able to do this without the need for custom code.
Something like this...
=SUM(IIF(Fields!Table.Value = "Plan", Fields!Total.Value,0))
-
SUM(IIF(Fields!Table.Value = "Actuals", Fields!Total.Value,0))
UPDATE for clarity
I have created a report based on your sample data and the above works as expected.
I created a dataset using the following query
DECLARE #t TABLE (WBSNumbers varchar(20), [Table] varchar(20), Account Varchar(20), Total float)
INSERT INTO #t
SELECT 'xxx', 'Plan', 'Capital', 96875 UNION ALL
SELECT 'xxx', 'Plan', 'Expense', 40625 UNION ALL
SELECT 'xxx', 'Actuals', 'Capital', 229949 UNION ALL
SELECT 'xxx', 'Actuals', 'Expense', 2848 UNION ALL
SELECT 'yyy', 'Actuals', 'Expense', 0
SELECT * FROM #t
I added a matrix with row groups for WBSNumbers and Account and a column group for Table.
I added a new column outside the column group with the expression stated above
I added an extra row for the headers but this was not really required - just to make it match the expected output more closely.
The final design looks like this.
The final output looked like this...
Other than the fact that the sample data does not match the supplied expected output for ABS yyyy this works as expected.

Related

I tested in my SQL Developer one case about "Subquery in Order By"

I have question about "Subquery in Order by clause". The below request returns the error. Is it means that Subquery in Order by clause must be scalar?
select *
from employees
order by (select * from employees where first_name ='Steven' and last_name='King');
Error:
ORA-00913: too many values
00913. 00000 - "too many values"
Yes, it means that if you use a subquery in ORDER BY it must be scalar.
With select * your subquery returns multiple columns and the DBMS would not know which of these to use for the sorting. And if you selected one column only, you would still have to make sure you only select one row of course. (The difference is that Oracle sees the too-many-columns problem immediately, but detect too many rows only when fetching the data.)
This would be allowed:
select * from employees
order by (select birthdate from employees where employee_id = 12345);
This is a scalar query, because it returns only one value (one column, one row). But of course this still makes as little sense as your original query, because the subquery result is independent from the main query, i.e. it returns the same value for every row in the table and thus no sorting takes effect.
A last remark: A subquery in ORDER BY makes very seldomly sense, because that would mean you order by something you don't display. The exception is when looking up a sortkey. E.g.:
select *
from products p
where type = 'shirt' and color = 'blue' and size in ('S', 'M', 'L', 'XL')
order by (select sortkey from sizes s where s.size = p.size);
It means that valid options for ORDER BY clause can be
expression,
position or
column alias
A subquery is neither of these.

Trying to display top 3 amount from a table using sql query in oracle 11g..column is of varchar type

Am trying to list top 3 records from atable based on some amount stored in a column FTE_TMUSD which is of varchar datatype
below is the query i tried
SELECT *FROM
(
SELECT * FROM FSE_TM_ENTRY
ORDER BY FTE_TMUSD desc
)
WHERE rownum <= 3
ORDER BY FTE_TMUSD DESC ;
o/p i got
972,9680,963 -->FTE_TMUSD values which are not displayed in desc
I am expecting an o/p which will display the top 3 records of values
That should work; inline view is ordered by FTE_TMUSD in descending order, and you're selecting values from it.
What looks suspicious are values you specified as the result. It appears that FTE_TMUSD's datatype is VARCHAR2 (ah, yes - it is, you said so). It means that values are sorted as strings, not numbers - and it seems that you expect numbers. So, apply TO_NUMBER to that column. Note that it'll fail if column contains anything but numbers (for example, if there's a value 972C).
Also, an alternative to your query might be use of analytic functions, such as row_number:
with temp as
(select f.*,
row_number() over (order by to_number(f.fte_tmusd) desc) rn
from fse_tm_entry f
)
select *
from temp
where rn <= 3;

Is there a way to get list of all column values from multiple datasets

We have 2 datasets. Both datasets have a column called Office. Say Dataset1 Office column has values London, Liverpool and Dataset2 the Office column has values Washington, California.
Is there any way in SSRS to do something like UNION ALL (but within SSRS) that is produce a list of all Office values in one table column?
There may be much more elegant ways of doing this but this is all I could come up with..
You need to have a unique numeric id for each record
Assuming you cannot simply union these together in your dataset query, if you can add a numeric ID to each record then you can do it (albeit a bit clunky)
To start with I created two datasets ds1 and ds2 to hold the two lists of office names.
For example the first dataset query was just this...
DECLARE #t TABLE(OfficeID int, Office varchar(20))
INSERT INTO #t VALUES
(1, 'London'),
(2, 'Liverpool')
SELECT * FROM #t
and the second was this.
DECLARE #t TABLE(OfficeID int, Office varchar(20))
INSERT INTO #t VALUES
(10, 'Washington'),
(11, 'California')
SELECT * FROM #t
As you can see, each office now has a unique numeric id
Next I needed another dataset with a list of number that covered the entire range of office ids. In this example the range is just 20 numbers
note: this work on SQL Server for other systems you'll have to come up with another method of getting a list of numbers
So, the query for dsNums is
declare #n table(num int)
insert into #n
select top 20 row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2
SELECT * FROM #n
Next I added a table to the report, reduced it to two columns and bound it to dsNums. The first column is just the [num] field.
The second is an expression that does two lookups and takes the first non blank result. The expression was
=IIF(
LEN(LOOKUP(Fields!num.Value, Fields!OfficeID.Value, Fields!Office.Value, "ds1"))>0
, LOOKUP(Fields!num.Value, Fields!OfficeID.Value, Fields!Office.Value, "ds1")
, LOOKUP(Fields!num.Value, Fields!OfficeID.Value, Fields!Office.Value, "ds2")
)
If we run the report now we get..
Finally we need to hide the empty rows. To do this I set the Row Visibilty expression to
=LEN(ReportItems!LookupResult.Value) = 0
The result is this (obviously you don't need the num column but it was just for illustration)

pl-sql include column names in query

A weird request maybe but. My boss wants me to create an admin version of a page we have that displays data from an oracle query in a table.
The admin page, instead of displaying the data (query returns 1 row), needs to return the table name and column name
Ex: Instead of:
Name Initial
==================
Bob A
I want:
Name Initial
============================
Users.FirstName Users.MiddleInitial
I realize I can do this in code but would rather just modify the query to return the data I want so I can leave the report generation code mostly alone.
I don't want to do it in a stored procedure.
So when I spit out the data in the report using something like:
blah blah = MyDataRow("FirstName")
I can leave that as is but instead of it displaying "BOB" it would display "Users.FirstName"
And I want to do the query using select * if possible instead of listing all the columns
So for each of the columns I am querying in the * , I want to get (instead of the column value) the tablename.ColumnName or tablename|columnName
hope you are following- I am confusing myself...
pseudo:
select tablename + '.' + Columnname as WhateverTheColumnNameIs
from Table1
left join Table2 on whatever...
Join Table_Names on blah blah
Whew- after writing all this I think I will just do it on the code side.
But if you are up for it maybe a fun challenge
Oracle does not provide an authentic way(there is no pseudocolumn) to get the column name of a table as a result of a query against that table. But you might consider these two approaches:
Extract column name from an xmltype, formed by passing cursor expression(your query) in the xmltable() function:
-- your table
with t1(first_name, middle_name) as(
select 1,2 from dual
), -- your query
t2 as(
select * -- col1 as "t1.col1"
--, col2 as "t1.col2"
--, col3 as "t1.col3"
from hr.t1
)
select *
from ( select q.object_value.getrootelement() as col_name
, rownum as rn
from xmltable('//*'
passing xmltype(cursor(select * from t2 where rownum = 1))
) q
where q.object_value.getrootelement() not in ('ROWSET', 'ROW')
)
pivot(
max(col_name) for rn in (1 as "name", 2 as "initial")
)
Result:
name initial
--------------- ---------------
FIRST_NAME MIDDLE_NAME
Note: In order for column names to be prefixed with table name, you need to list them
explicitly in the select list of a query and supply an alias, manually.
PL/SQL approach. Starting from Oracle 11g you could use dbms_sql() package and describe_columns() procedure specifically to get the name of columns in the cursor(your select).
This might be what you are looking for, try selecting from system views USER_TAB_COLS or ALL_TAB_COLS.

How to create select SQL statement that would produce "merged" dataset from two tables(Oracle DBMS)?

Here's my original question:
merging two data sets
Unfortunately I omitted some intircacies, that I'd like to elaborate here.
So I have two tables events_source_1 and events_source_2 tables. I have to produce the data set from those tables into resultant dataset (that I'd be able to insert into third table, but that's irrelevant).
events_source_1 contain historic event data and I have to do get the most recent event (for such I'm doing the following:
select event_type,b,c,max(event_date),null next_event_date
from events_source_1
group by event_type,b,c,event_date,null
events_source_2 contain the future event data and I have to do the following:
select event_type,b,c,null event_date, next_event_date
from events_source_2
where b>sysdate;
How to put outer join statement to fill the void (i.e. when same event_type,b,c found from event_source_2 then next_event_date will be filled with the first date found
GREATLY APPRECIATE FOR YOUR HELP IN ADVANCE.
Hope I got your question right. This should return the latest event_date of events_source_1 per event_type, b, c and add the lowest event_date of event_source_2.
Select es1.event_type, es1.b, es1.c,
Max(es1.event_date),
Min(es2.event_date) As next_event_date
From events_source_1 es1
Left Join events_source_2 es2 On ( es2.event_type = es1.event_type
And es2.b = es1.b
And es2.c = es1.c
)
Group By c1.event_type, c1.b, c1.c
You could just make the table where you need to select a max using a group by into a virtual table, and then do the full outer join as I provided in the answer to the prior question.
Add something like this to the top of the query:
with past_source as (
select event_type, b, c, max(event_date)
from event_source_1
group by event_type, b, c, event_date
)
Then you can use past_source as if it were an actual table, and continue your select right after the closing parens on the with clause shown.
I end up doing two step process: 1st step populates the data from event table 1, 2nd step MERGES the data between target (the dataset from 1st step) and another source. Please forgive me, but I had to obfuscate table name and omit some columns in the code below for legal reasons. Here's the SQL:
INSERT INTO EVENTS_TARGET (VEHICLE_ID,EVENT_TYPE_ID,CLIENT_ID,EVENT_DATE,CREATED_DATE)
select VEHICLE_ID, EVENT_TYPE_ID, DEALER_ID,
max(EVENT_INITIATED_DATE) EVENT_DATE, sysdate CREATED_DATE
FROM events_source_1
GROUP BY VEHICLE_ID, EVENT_TYPE_ID, DEALER_ID, sysdate;
Here's the second step:
MERGE INTO EVENTS_TARGET tgt
USING (
SELECT ee.VEHICLE_ID VEHICLE_ID, ee.POTENTIAL_EVENT_TYPE_ID POTENTIAL_EVENT_TYPE_ID, ee.CLIENT_ID CLIENT_ID,ee.POTENTIAL_EVENT_DATE POTENTIAL_EVENT_DATE FROM EVENTS_SOURCE_2 ee WHERE ee.POTENTIAL_EVENT_DATE>SYSDATE) src
ON (tgt.vehicle_id = src.VEHICLE_ID AND tgt.client_id=src.client_id AND tgt.EVENT_TYPE_ID=src.POTENTIAL_EVENT_TYPE_ID)
WHEN MATCHED THEN
UPDATE SET tgt.NEXT_EVENT_DATE=src.POTENTIAL_EVENT_DATE
WHEN NOT MATCHED THEN
insert (tgt.VEHICLE_ID,tgt.EVENT_TYPE_ID,tgt.CLIENT_ID,tgt.NEXT_EVENT_DATE,tgt.CREATED_DATE) VALUES (src.VEHICLE_ID, src.POTENTIAL_EVENT_TYPE_ID, src.CLIENT_ID, src.POTENTIAL_EVENT_DATE, SYSDATE)
;

Resources