I have a simple stored procedure that is pulling data for a SS report. One of the columns uses only a letter for the value. I would like to spell out the word the letter represents for the report. The procedure looks something like this...
ALTER PROCEDURE RPT_MYREPORT
{
#PID INT=1234567
}
AS BEGIN
SELECT
SSN,
DOB,
PID,
Name,
MaritalStatus
FROM
Customers
END
Obviously theres more to it but thats the basic setup. Marital Status is either an "S" for Single or "M" for Married. I would like to have these values spelled out for my report. Anyone know how?
Add a lookup table to your database containing the letter and the name/description you want to display. Join your main table to this in the query supplying the data to the report.
E.g. for the lookup table:
CREATE TABLE Marital_Status (
marital_status_code char(1) PRIMARY KEY,
marital_status_name char(7)
)
then add the lookup data
INSERT Marital_Status(marital_status_code, marital_status_name)
VALUES ('S', 'Single')
INSERT Marital_Status(marital_status_code, marital_status_name)
VALUES ('M', 'Married')
If you set the relationship between the main and lookup tables it also serves as data validation when new rows are inserted.
You have 2 options:
Convert value to word inside SP (case MaritalStatus when 'S' then 'Single' when 'M' then 'Married' for example)
Convert value to word inside report definition (expression based on iif function)
Related
We have a company website where BI reports are hosted. For one particular report (and possibly for others, if this can be made to work), there is a requirement to:
a) retrieve saved values for report parameters
and
b) to save any changed values for report parameters
I know that parameter values can be retrieved from data by setting the Default Values to "Get values from a query".
However, what I would like to do is when the user presses View Report that the values that [s]he has selected should be saved to a database so that these will then form the default values for the next user.
Can this be done? There doesn't seem to be any way "out of the box".
This is quite simple.
Lets assume you had a table of Countries that drive your parameter's available values and that this table myCountryTable has two columns CountryID and CountryName.
You available values dataset would be something simple like
SELECT * FROM myCountryTable
CountryID would be the parameter value and CountryName would be the parameter label.
OK so you will have probably done all the above already.
Now, in your main dataset query simply add an INSERT statement before you main query runs.
So, if you dataset query looks like this..
SELECT * FROM SomeBigTable WHERE CountryID in (#CountryID)
you would change it to something like
INSERT INTO myLogTable
SELECT CountryID, CountryName FROM myCountryTable WHERE CountryID IN (#CountryID)
-- original query follows
SELECT * FROM SomeBigTable WHERE CountryID in (#CountryID)
Note: If you cannot change your main dataset query for whatever reason, you can do this in a separate dataset but there are a few things you will have to do
First: Change the sql so that it returns a value at the end, anything will do e.g.
INSERT INTO myLogTable
SELECT CountryID, CountryName FROM myCountryTable WHERE CountryID IN (#CountryID)
SELECT 1 as myReturnValue
Second: You must bind this dataset to something on the report such as a table or list, this is to make sure the query only executes when the report is executed, not when parameters are changed.
You could store parameters and their values every time the report is executed.
Note: Some of these integrated SQL functions maybe do not exist on your server, which depends on the server version. If that is the case, it is easy to find alternative, or even create your own function.
For example, at the end of every stored procedure that is used by report place this part of SQL query that uses newly created table dbo.ReportParameterValuePairs:
INSERT INTO dbo.ReportParameterValuePairs
(ReportName, ParameterValuePair, ExecutionDateTime)
VALUES(
'MyReport',
'$$$parameter1$$$: ' + #parameter1 + ',' +
'$$$parameter2$$$: ' + #parameter2,
GETDATE())
Later on will be clear why are these data stored and why in this way.
Nest step would be creating procedure which will retrieve value of some parameter during the last execution of report:
CREATE PROCEDURE spRetrieveReportParameterValue
#parameter NVARCHAR(100),
#report NVARCHAR(100)
AS
BEGIN
-- this is an example
DECLARE #parameters NVARCHAR(MAX) = '$$$parameter1$$$: value1, $$$parameter2$$$: value2'
-- in reality parameter-value pairs will be retrieved from database
--DECLARE #parameters NVARCHAR(MAX) =
-- (SELECT TOP 1 ParameterValuePair
-- FROM dbo.ReportParameterValuePairs
-- WHERE ReportName = #report
-- ORDER BY ExecutionDateTime DESC)
--SELECT #parameters
DECLARE #parameterValuePair NVARCHAR(200) =
(SELECT * FROM STRING_SPLIT (#parameters, ',')
WHERE
VALUE LIKE '%$$$' + #parameter + '$$$%')
--SELECT #parameterValuePair
DECLARE #value NVARCHAR(100) =
(SELECT * FROM STRING_SPLIT (#parameterValuePair, ':') WHERE value NOT LIKE '%$$$%')
SELECT TRIM(#value) AS ParameterValue
END
Parameters of the procedure are: parameter which value is needed, report that is executing.
Parameter-value pairs are stored in a single string. To access that data search table dbo.ReportParameterValuePairs for currently executing report. Order data by date and time of execution, starting from the latest.
Parameter-value pairs string will be split using ,. The result of this split is a table that consists of parameter-value pairs. Distinction between parameters and their values is $$$ mark. Because of that the condition in query is VALUE LIKE '%$$$' + #parameter + '$$$%'.
Variable #parameterValuePair now stores desired parameter and its value.
After another one split, this time using : because it separates value from parameter name, the result of split will be two rows. One contains parameter and $$$ marks ($$$[parameter]$$$) and the other contains the value. Using condition WHERE value NOT LIKE '%$$$%' parameter's value will be stored to #value variable.
Last step of the procedure is to trim the value in case there are empty spaces at the end and at the beginning of the #value and return it as ParameterValue.
In order to retrieve this value to report create DataSet for every report parameter. This DataSet will supply parameter with default value:
right click on DataSets
choose Add Dataset
choose tab/card Query
name DataSet
select Data source
for query type choose Text
enter spRetrieveReportParameterValue 'parameter1', 'MyReport' where parameter1 is name of parameter which last value will be retrieved
click Refresh Fields
The last step is to set default value to the parameter:
right click on parameter
select Parameter Properties
choose card/tab Default Values
choose option Get values from a query
for Dataset choose newly created dataset
for Value field choose ParameterValue
This should be the result:
So I have a base table - TRAINING, which has 100 columns. Some of the columns will be completely NULL and some will contain Values. So say COLUMN 1-20 are null and COLUMN 21-100 are not NULL.
I have another table called - CONFIGURATION. It has only one column of type VARCHAR. This table contains the name of those columns from the TRAINING table that are not NULL. So it'll contain values - COLUMN 21-100.
What I want to do is- fetch the data of only those columns that are not NULL. So I want the output as the data points contained in table COLUMN 21-100. This number may be different every time and it can also be interleaved, say COLUMN 1-10 is NULL and COLUMN 11-25 not NULL and the remaining again NULL.
I am thinking of implementing inner Join but I do not have the table structure required for it.
Please provide some hint.
Thanks.
You need to create dynamic SQL for that.
First step - create ALL_COLUMNS variable of VARCHAR(5000) data type.
From your CONFIGURATION table select column names which you want to query. Then use STRING_AGG function to aggregate them into single value (in my example COL1 is column from CONFIGURATION table). Assign output to the ALL_COLUMNS variable
Second step use EXECUTE IMMEDIATE to run dynamic SQL. Add ALL_COLUMNS variable as input for that query.
Here is the examplary code:
DO
BEGIN
/* First Step - create string with all column names separated by comma*/
DECLARE ALL_COLUMNS VARCHAR(5000);
SELECT STRING_AGG(COL1,',' ORDER BY COL1) INTO ALL_COLUMNS FROM CONFIGURATION;
/*Second Step - create dynamic SQL including variable from First Step*/
EXECUTE IMMEDIATE ('SELECT ' || :ALL_COLUMNS || ' FROM "TRAINING" ');
END
I would like to have the results of my query (that returns one row) to be displayed in text like this:
columnA: value
columnB: value
columnC: value
as happens in mysql when using
select * from tablename \G
Is there a way to do this? The reason for this is that it is helpful to be able to print out one record with columns and values for example data or to share a record from a table that has many columns and which would be hard to view across the screen.
It's not quite so simple as your MySQL example, but you can do an unpivot to get what you want.
---------------
-- TEST SCHEMA
---------------
declare #tablename as Table(keyvalue varchar(2), dataColA varchar(2), dataColB varchar(2), dataColC varchar(2))
insert into #tablename select '01', '02', '03', '04'
---------------
-- UNPIVOT
---------------
select dataColumns, dataValues
from #tablename
unpivot
(
dataValues
for dataColumns in (keyvalue, dataColA, dataColB, dataColC)
) u;
The easiest way to accomplish what I want is to
execute the query to a results grid, limit to top 1 if necessary to ensure only one row is returned,
right-click in top left corner, Copy with Headers
open Excel, paste
select what was just pasted and copy again within Excel
go to blank area of workbook or new worksheet and Paste Special, Transpose
This will create one row per database query column with column name in column A and value in column B.
I'm trying to create a trigger which will capture any event that will occur when I update any column in the table before and after updating, let's say I have 4 columns:
first_name address city country
Let's say I edited first_name lets say Jack to Henk.
It should insert in another table the command (i.e. update) ,time , description but inside the description I want it to write Jack was changed to John by current user(i.e using the current-user () function),if it is a city being updated from Mechinkova to Tostov, it should do the same do with other columns.
I know I want to have to add the concat function inside the trigger, I want it to be like this for example:
DROP TRIGGER IF EXISTS adminpanel.soft//
CREATE TRIGGER adminpanel.soft BEFORE UPDATE ON adminpanel.aggrement
FOR EACH ROW
BEGIN
INSERT INTO adminpanel.aggretrigger(cmd, time, cmd_user, last_name, city) VALUES("INSERT", NOW(), CURRENT_USER(), new.last_name, new.city);
END
//
What you are asking for is an audit trigger. It is very easy to implement.
Let us first slightly modify your main table. Let's add a field id of integer datatype as the primary key to the table, so your table would look like:
tablename
( id integer PK
, first_name varchar
, address varchar
, city varchar
, country varchar
)
Now, you will need a table, say UNIVERSAL_AUDIT_ENTRY table that will store the changes made to the data in your schema.
From what experience I have, I suggest you create this table as follows:
universal_audit_entry
( universal_audit_entryid integer PK
, table_name varchar -- captures the name of the table
, column_name varchar -- captures the name of the column
, entry_type varchar -- captures the event, e.g., 'INSERT' or 'UPDATE'
, primary_key_value integer -- captures, e.g., the value in tblename.id
, from_str varchar -- captures the value that was present before
, to_str varchar -- captures the value that was changed into
, timestamp datetime -- captures the timestamp of the event
, username varchar -- captures the name of user
)
Now with the universal_audit_entry table ready, your trigger should look somewhat like:
CREATE TRIGGER adminpanel.soft
BEFORE UPDATE ON adminpanel.aggrement
FOR EACH ROW
BEGIN
IF UPDATING(first_name) THEN
INSERT INTO universal_audit_entry VALUES
( 123 -- example for universal_audit_entryid
, 'TABLENAME'
, 'FIRST_NAME'
, 'UPDATE'
, new.id
, old.first_name
, new.first_name
, current_timestamp()
, current_user);
END IF;
END;
//
You can use similar logic to audit more columns in the same table and other tables also.
Note:
This code is not tested. I have added it here only for illustration purposes. This code for trigger is not supposed to be used directly.
new and old are the pseudo-records that are generated during an update statement. These records correspond to the rows that are being updated. :new means the row after the update statement runs and :old means the row before the update statement runs. This works in Oracle. Kindly make sure if it works in MySQL also.
EDIT
You can read more about MySQL triggers here. Read more about audit trail here and this SO question.
I have a stored procedure that returns three columns worth of data to our SSRS report. The stored procedure does not alias two of those columns, so they are returned unnamed. Here is an example of what the return dataset might look like:
[FundName] [blank] [blank]
Abc col2val1 col3val1
Def col2val2 col3val2
Ghi col2val3 col3val3
I'd like to be able to use an expression in SSRS to retrieve the values from column 2 and 3. Here's an example of what retrieving data from FundName would look like:
=Fields!FundName.Value
Is there any way to replace the column name (in this example, FundName) with say, the index or position of the column, like so:
=Fields![0].Value //returns FundName values
=Fields![1].Value //returns column 2 values
=Fields![2].Value //returns column 3 values
Thank you in advance.
If your stored procedure is not returning the columns names then you can't create a dataset in SSRS as it will throw an error
An item with the same key is already been added
and there is now way you can reference the column name using index in SSRS
Fortunately, a way to accomplish this has been found. Since our stored procedure could not be changed and it did not return enough information for SSRS to generate a report (missing column names in the resulting DataSet), we changed the way our DataSet gets populated.
In the DataSet query builder, we created a temporary table and had the stored procedure insert into that temporary table. Once inserted, we selected all the values in our temporary table which populated the DataSet. Now the DataSet has 3 columns with 3 column names to be used by our report.
CREATE TABLE #tempTable (
FundName varchar(50),
col2 dec(15,4),
col3 char(8)
)
insert into #tempTable
exec storedProcedureName
select * from #tempTable
drop table #tempTable
Then you can access those column values in an expression just like before:
=Fields!FundName.Value //returns FundName values
=Fields!col2.Value //returns column 2 values
=Fields!col3.Value //returns column 3 values
I hope this helps anyone else with this particular issue.