I need help with querying my business rules in SQL!
I have created couple of business rules in MDS web service to validate my master data and found out that 2 % of my data is not complying with the rules. Now I have created a SQL subscription view to report on the invalid data in PowerBI. In my PowerBI report I need to tell the business user why the data is invalid but I cannot since the subscription view only tells where the data is invalid but not why the data is invalid. So I need to know how I might query my business rules from MDS database in SQL and map it with my PowerBI data model. Is there a way to query the list of business rules from MDS database?
OK, so there are multiple ways to go about this. Here are some solutions, pls choose one that suits your scenario.
1. SQL - List of all Business Rules
The following query will retrieve the list of all Active Business Rules created in MDS.
SELECT *
FROM [MDM].[mdm].[viw_SYSTEM_SCHEMA_BUSINESSRULES]
WHERE Model_Name = 'YourModelName'
AND BusinessRule_StatusName = 'Active'
You can, of course, further filter by Entity_Name, etc.
The important columns in your case are going to be:
[BusinessRule_Name]
[BusinessRule_Description]
[BusinessRule_RuleConditionText]
[BusinessRule_RuleActionText]
Note: The challenge in your scenario, I think, is going to be that the Subscription View of the entity does not have IDs of the exact Business Rules that failed. So I'm not sure how you'll tie these 2 together (failing Rows -> List of Business Rules). Also remember that each row may have more than 1 business rule that failed.
2. using View viw_SYSTEM_USER_VALIDATION
This is a view that has a historical list of all business rules (+row info) that failed. You may use the view in this way:
SELECT
DISTINCT ValidationIssue_ID, Version_ID, VersionName, Model_ID, ModelName, Entity_ID, EntityName, Hierarchy_ID, HierarchyName, Member_ID, MemberCode, MemberType_ID, MemberType, ConditionText, ActionText, BusinessRuleID, BusinessRuleName, PriorityRank, DateCreated, NotificationStatus_ID, NotificationStatus
FROM [MDM].[mdm].[viw_SYSTEM_USER_VALIDATION]
WHERE --CAST(DateCreated as DATE) = CAST(GETDATE() as DATE) AND
ModelName = 'YourModelName'
--AND EntityName IN ('Entity_1','Entity_2') -- Use this to Filter on specific Entities
Here, use the columns Model_ID, Entity_ID and Member_ID/MemberCode to identify the specific model, entity & row that failed.
Columns BusinessRuleName, ConditionText & ActionText will give your users additional info on the Business Rule that failed.
Note:
One issue with using this view is that even though, let's say, your failure condition was resolved the next day by the user, the view will still show that on a certain date, a validation had failed. (via column DateCreated).
Also note that the same failed data row will appear multiple times here if multiple Business Rules on the same row failed validation (there will be different BusinessRuleID/Name, etc). Just something to take note of.
Similarly, the same row may appear multiple times if it has failed again & again at different times. To workaround this, and if your final report can do with that, add a WHERE clause on the DateCreated column so that you only get to see any row that Failed today. The commented out line of code <--CAST(DateCreated as DATE) = CAST(GETDATE() as DATE) AND> does the same. If you can't use that, just make sure the data row are distinct. However, if you do this, remember that if something Failed yesterday (and is still in the Failed status), it may not show up.
My suggestion would be to use a slightly modified version of Solution #2:
Get the list of Failed Rows from your Subscription View (the data row's ValidationStatus is actually still 'Failed'), then JOIN with viw_SYSTEM_USER_VALIDATION making sure that you only select the row with MAX(DateCreated) value (of course for the same data row AND Business Rule).
Best of luck and if you find anything else while solving this issue, do share your learning here with all of us.
Lastly, if you found this useful, pls remember to Mark it as the Answer :)
Related
I am unsure how to design security policies for a following system including counters in postgres/supabase. My database includes two tables:
Users:
uuid|name|follower_counter
------------------------------
xyz |tobi| 1
Following-Relationship
follower| following
---------------------------
uuid_1 | uuid_2
Once a user follows a different user, I would like to use a postgres function/transaction to
Insert a new following-follower relationship
Update the followed users' counter
BEGIN
create follower_relationship(follower_id, following_id);
update increment_counter_of_followed_person(following_id);
END;
The constraint should be that the users table (e.g. the name column) can only be altered by the user owning the row. However, the follower_counter should open to changes from users who start following that user.
What is the best security policy design here? Should I add column security or should exclude the counters to a different table?
Do I have to pass parameters to the "block transaction" to ensure that the update and insert functions are called with the needed rights? With which rights should I call the block function?
It might be better to take a different approach to solve this problem. Instead of having a column dedicated to counting the followers, I would recommend actually counting the number of followers when you query the users. Since you already have Following-Relationship table, we just need to count the rows within the table where following or follower is the querying user.
When you have a counter, it might be hard to keep the counter accurate. You have to make sure the number gets decremented when someone unfollows. What if someone blocks a user? What if a user was deleted? There could be a lot of situations that could throw off the counter.
If you count the number of followings/followers on the fly, you don't need to worry about those situations at all.
Now obvious concern with this approach that you might have is performance, but you should not worry too much about it. Postgres is a powerful database that has been battle tested for decades, and with a proper index in place, it can easily perform these query on the fly.
The easiest way of doing this in Supabase would be to create a view like this the following. Once you create a view, you can query it from your Supabase client just like a typical table!
create or replace view profiles as
select
id,
name,
(select count(*) from following_relationship where followed_user_id = id) as follower_count,
(select count(*) from following_relationship where following_user_id = id) as following_count
from users;
I am using Oracle Business Intellgience (12c) and let's say I have a report resulted from an execution of the following query
select code_filial, max(paid) as maximum_pay
from leads_history
group by code_filial
It will return a table with highest budget value related to the each filial. Now what i want is the following: when i click to max(paid) result in a table, another table should appear with the information about max(paid) account. I tried master-detail relationship, but couldn't succeed.
Can anyoune help with that?
That's out-of-the-box functionality. As soon as you make a navigation action link to another analysis where your code_filial is set to "is prompted" the context will be passed and the analysis filtered.
I use PostgreSQL10 and I want to built queries that have multiple optional parameters.
A user must input area name, but then it is optional to pick none or any combination of the following event, event date, category, category date, style
So a full query could be "all the banks (category), constructed in 1990 (category date) with modern architecture (style), that got renovated in 1992 (event and event date) in the area of NYC (area) ".
My problem is that all those are in different tables, connected by many-to-many tables, so I cannot do something like
SELECT * FROM mytable
WHERE (Event IS NULL OR Event = event)
I dont know if any good will come if I just join four tables.
I can easily find the area id, since it is required, but I dont know what the user chose, beside that.
Any suggestions on how to approach this, with Postgre?
Thanks
It might be optimal to build the entire query dynamically and only join in tables that you know you're going to need in order to apply the user's filters, but it's impractical. You're better off creating a view on the full set of tables. Use LEFT OUTER JOINs to ensure that you don't accidentally filter out valid combinations and index your tables to ensure that the query planner can navigate the table graph quickly. Then query the view with a WHERE clause reflecting only the filters you want to apply.
If performance becomes a concern and you don't mind having non-realtime data, you could use a materialized view to cache the results. Materialized views can be indexed directly, but this is a pretty radical change so don't do this unless you have to.
My question is a variation on one already asked and answered (TSQL Delete Using Inner Joins) but I have a different level of complexity and I couldn't see a solution to it.
My requirement is to delete Special Prices which haven't been accessed in 90 days. Special Prices are keyed on Customer ID and Product ID and the products have to matched to a Customer Order Detail table which also contains a Customer ID and a Product ID. I want to write one function that will look at the Special Price table for each Customer, compare each Product for that Customer with the Customer Order Detail table and if the Maximum Order Date is more than 90 days earlier than today, delete it from the Special Price table.
I know I can use a CURSOR (slow but effective) but would prefer to have a single query like the one in the TSQL Delete Using Inner Joins example. Any ideas and/or is more information required?
I cannot dig more on the situation of your system but i think and if it is ok for you, check MERGE STATEMENT, it might be a help instead of using cursors. check this Link MERGE STATEMENT
I have arrived at this dilemma via a tortuous and frustrating route, but I'll start with where I am right now. For information I'm using VS2010, Silverlight 5 and the latest versions of the Silverlight and RIA Toolkits, SDKs etc.
I have a view in my database (it's actually now an indexed view, but that has made no difference to the behaviour). For testing purposes (and that includes testing my sanity) I have duplicated the view as a Table (ie identical column names and definitions), and inserted all the view rows into the table. So if I SELECT * from the view or the table in Query Analyzer, I get identical results. So far so good.
I create an EDF model in my Silverlight Business Application web project, including all objects.
I create a Domain Service based on the model, and it creates ContextTypes and metadata for both the View and the Table, and associated Query objects.
If I populate a Silverlight ListBox in my Silverlight project via the Table Query, it returns all the data in the table.
If I populate the same ListBox via the View Query, it returns one row only, always the first row in the collection, however it is ordered. In fact, if I delve into the inner workings via the debugger, when it executes the ObjectContext Query in the service, it returns a result set of the correct number of rows, but all the rows are identical! If I order ascending I get n copies of the first row, descending I get n copies of the last row.
Can anyone put me out of my misery here, and tell me why the View doesn't work?
Ade
OK, well that was predictable - nearly every time I ask a question on a forum I stumble across the answer while I'm waiting for responses to flood in!
Despite having been through the metadata and model.designer files and made sure that all "view" and "table" class/method definitions etc were identical, it was still showing the exasperating difference in behaviour between view and table queries. So the problem just had to be caused by the database, right?
Sure enough, I hadn't noticed myself creating NOT NULL columns when I created the "identical" Table version of my view! Even though I was using a SELECT NEWID() to create a unique key column on the view, the database insisted that the ID column in the view was NULLABLE, and it was apparently this which was causing the problem.
To save some storage space I switched from using NEWID() to using ROW_NUMBER() to create my key column, but still had the "NULLABLE" property problem. SO I then changed it to
SELECT ISNULL(ROW_NUMBER() (OVER...) , -1)
for the ID column, and at last the column in the view was created NOT NULL! Even though neither NEWID() nor ROW_NUMBER() can ever generate NULL output, it seems you have to hold SQL Server's hand and reassure it by using the ISNULL operator before it will believe itself.
Having done this, deleted/recreated my model and service files, everything burst into glorious technicolour life without any manual additions of [Key()] properties or anything else. The problem had been with the database all along, and NOT with the Model/Service/Metadata definitions.
Hope this saves someone some time. Now all I need to do is work out why the original stored procedure method I started with two days ago doesn't work - but at least I now have a hint!
Ade