I'm new to reporting svcs and I'm writing a report based on a report model (.smdl) created in VS.NET 2008. I seem to be missing out on the report builder query view's analog to a "left join." Model is very simple:
Three entities:
Cust (custid, custname)
Ord (ordid, custid, orddate, ...)
Charge (chargeid, ordid, chargetype, chargevalue...)
Think of a "charge" as an optional cost (a special charge) associated with an order -- some orders have them, some don't.
Model was auto-generated from views (.dsv) which accurately indicate the relationships between cust and ord, and between ord and charge. I noted that when designing the view relationships there was no kind of option to indicate (for example) that the relationship should be treated as a "left join".
Now I jump to Report Builder 2 (RB2) to design a report based on this model. My goal is to simply list for each order: customer name, order date, charge type, charge value (i.e., order row would repeat if it had more than one charge type). I want ALL orders listed, even if an order doesn't have any charges -- what I would consider a "left join" in the traditional sense.
I use RB2's Query Designer to create the dataset, and merely select (i.e., double-click) the entities I want as fields in the report: custname, orddate, chargetype, chargeval. I then create a simple table in the report based on this dataset.
When running the report, I get only those orders which actually have charges. I was rather hoping to get all orders. Is there a way I can specify that?
Thank you,
Bill Dawson
I got an answer via Sql Server forums:
http://social.msdn.microsoft.com/Forums/en-US/sqlreportingservices/thread/20d4b4fd-dc0b-428e-a5b8-aedf5c53d340
Relevant portion here from Aaron Meyers:
The key here is that all report model queries are centered around a "base entity" and each row at the detail level in your report represents a row in this base entity. You may note that in your model, there is no entity which corresponds to "a charge for an order or just the order if it has no charges". You need to explicitly create this Order-Charge entity in the model, based on a Named Query in the DSV. This named query can just select the keys from the Ord table and the Charge table with a LEFT OUTER JOIN between the two. You then create relationships from these keys to the Ord and Charge tables, and update the model (right-click on Model root node and Autogenerate).
When you start with details from Ord and navigate through the new role to Charge and select additional details, Report Builder will choose the Order-Charge entity as the root/base entity of the report.
We are considering functionality for a future release to allow creating these types of queries directly in Report Builder without requiring the model designer to explicitly create the LEFT OUTER JOIN entity.
I believe the left joins happen based on the order you add fields onto the query designer canvas. As long as you add customer fields, then order fields, then charge fields, you should be right.
You can verify the actual query that was run using SQL Profile which is very handy for debugging these sorts of things.
We can implement LEFT JOIN into the report model between the two entities by using the Cardinality property for an entity's role.
For example, let say we have two entities Customer and Order then.
Customer-->Order role should have Optional One(source)-->Optional Many(Target) {Because 1 customer can have 0 or many Orders}
Order-->Customer role should have Optional Many(source)-->Optional One(Target) {vice versa}
Related
I am looking for help with database design for a small project I am working on.
In short what I am trying to achieve is to have say the following tables:
Paddocks
Paddock ID
Paddock Name
Paddock Size
etc.
Cattle
Herd ID
Herd Name
Number of cows
Current Paddock
Cattle_Movements
Herd Name
Current Paddock
New Paddock
Date
etc.
I was hoping to have the 'Cattle_Movements' table be like a summary of all movements of a herd of cattle. And when a herd is moved from one paddock to another it would update the 'Current Paddock' field in the 'Cattle' table.
At this stage I am trying to workout the relationships, queries and high level process that I will need to implement.
Any help will be greatly appreciated.
Start by setting up a normalized table structure. make the tables below and hook them together with the relationships tool on the ribbon under database tools-relationships. To create a relationship drag the primary key from one table to the corresponding and same named foreign key in the table that will be the many side of the relationship. In the pop up make sure to check the enforce referential integrity, cascade update, and cascade delete checkboxes.
I've highlighted the two "Many to Many Relationships" in this normalization. HerdsPaddocks is a more generic name for the CattleMovements Table. There are other possible normalized table structures, but the subtle differences are beyond the scope of this answer. When you are ready, look up table normalization and Many to Many Relationships.
Next, Close the Relationships tool, select a table from the sidebar and on the ribbon under Create hit create form. Do this for all the tables. Now we have a working database but you need to learn how to use it. So play!
Below I gave some play suggestions, but just play with everything until you figure out how to use the forms to (add, search, edit) cows, herds, and paddocks. Also learn why you should delete the primary keys from all the forms and how to replace the foreign keys like CattleType in the Cattle Table with the user friendly CattleTypeDesscription from the CattleTypes Table.
Start with the Herds table and enter some random herds. (pro tip: never add data to the table directly except when playing the error rate is too high). Then Open the herds form where you can browse and edit the herds.
Play tips: In the Table Herds HerdID is both an autonumber and a primary key. It behaves differently from the other columns. Check it out. after that delete the HerdID textbox from the form and see what happens(a good thing). How do you add herds using the Herds Form?
Moving on to playing with the Cattle form, first make sure to add a few CattleTypes to the CattleTypes table. Then at some point, try replacing the CattleTypeID in the Cattle Form with the CattleTypeDescription: https://btabdevelopment.com/how-to-change-a-text-box-to-a-combo-box-wont-work-with-data-access-page/
Also, note the Cattle Form has a subform allowing you to simultaneously assign/edit cattle assignments to herds.
Once you are comfortable adding and editing data, play with the query editor. For instance, to get how many cows are currently in Paddock holds10cattle (my dummy data).
query 1 showing the relevant data
results from query1:
Query 2 getting really close:
Query 3: which gives the number 2:
'Query 3 SQL from SQL pane of query designer
SELECT Count(Cattle.CowName) AS CountOfCowName
FROM Paddocks INNER JOIN ((Herds INNER JOIN (Cattle INNER JOIN CattleHerds ON Cattle.CattleID = CattleHerds.CattleID) ON Herds.HerdID = CattleHerds.HerdID) INNER JOIN HerdsPaddocks ON Herds.HerdID = HerdsPaddocks.HerdID) ON Paddocks.PaddockID = HerdsPaddocks.PaddockID
GROUP BY Herds.HerdName, Paddocks.PaddockName, HerdsPaddocks.HerdPaddockEndDate, HerdsPaddocks.HerdPaddockStartDate
HAVING (((Paddocks.PaddockName)="holds10cattle") AND ((HerdsPaddocks.HerdPaddockEndDate) Is Null) AND ((HerdsPaddocks.HerdPaddockStartDate)<Now()))
ORDER BY HerdsPaddocks.HerdPaddockStartDate;
Next Steps could include the specific paddock with a parameter and using the query in a report.
I want to design a database for events and track a lot of statistic about the it.
Option 1
Create one table for Events and put all my statistic column in it. Like number of male, number of female, number of unidentified gender, temperature that day, time it started, any fights, was the police called, and etc.
The query would be a very simple select * from events
Option 2
Create two tables, one for Events and one for EventsAttributes. In the Events table I would store important stuff like id, event title, and start/end time.
In EventsAttributes I would store all the event statistic and link them back to Events with a eventId foreign key.
The query would look like below. (attributeType == 1 would represent number of males)
select e.*,
(select ev.value from EventAttributes ev where ev.eventId = e.id and attributeType = 1) as NumberOfMale
from Events e
The query would be not be as straight forward as option 1, but I want to design it the right way and live with the messy query.
So which option is the right way to do it, and why (I'm not a database admin, but curious).
Thank you for your time.
I prefer using option 2 for designing database.
In that option(2), you apply the best practice of database normalization.
There are three main reasons to normalize a database:
The first is to minimize duplicate data.
The second is to minimize or avoid data modification issues
The third is to simplify queries.
For more details, read Designing a Normalized Database
You can create views (queries) based on this normalized database to support Option (1).
In this way, database will be ready for any future scaling.
Update:
You can use the the valuable operator pivot and common table expressions (CTE) to get eventAttributes1, eventAttributes2, ...
Suppose your tables are :events and event_attributes as described below:
events
----------
# event_id
event_title
start_date
end_date
event_attributes
-------------
#event_id
#att_type
att_value
# is primary key
-- using table expression (it's like a dynamic view)
with query as (
select e.event_id, e.event_title,a.att_type, a.att_value
from events e
join event_attributes a on e.event_id =a.event_id
)
select event_id , event_title,
[1] as eventAttributes1, -- list all eventAttributes1 numbered [1],[2],...
[2] as eventAttributes2
[3] as eventAttributes3
FROM query
PIVOT(SUM(att_value) FOR att_type IN ([1],[2],[3])) as pvt
For details on pivot read: Using PIVOT
For details Using Common Table Expressions
First of all I have to mention that I am modernising our ERP system that is build in-house. It handles everything from purchasing of parts, sale orders, quotes and inventory to invoicing and statistical data. The system is web based and heavily dependent on ORM. EloquentORM will be used in the redesign.
My main question is about the data model of certain entities that are very similar. Currently three of most widely interconnected entities in the app are: Orders, Products and Invoices.
1. Orders
In current DB design I have one big orders table in which there is a order_type attribute to distinct between different order types: Purchase orders, Sale orders, Quotes and Service orders. About 80% of fields are common to each order type and there are some specific fields for each order types. Currently at ~15k records.
2. Products
Similarly I have one big products table with an attribute product_type to distinct between different product types: Finished products, Services, Assemblies and Parts. Again there is a fair % of fields that are common throughout all product types and some that are specific to different product type Currently at ~7k records.
3. Invoices
Again one table invoices with invoice_type attribute to distinct between 4 invoice types: Issued invoices (for things we sell), Received invoices (for things we buy), Credit notes and Avans Invoices. More or less all invoice types use the same fields. Currently at ~15k records.
I am now trying to decide which is the optimal way for this kind of DB model. I see three options:
1. Single Table Inheritance
Leave as is, everything in the same table. It feels kind of awkward to always filter records like where order_type = 'Sale order' to display right orders in the right place in GUI... Also when doing sale and purchase analytics I need to include the same where condition to fetch right orders. Seems wrong!
2. Class Table Inheritance
Have a master tables orders, products and invoices with common set of fields between each of entity types and then one-to-one child relation tables for every different type of each entity: sales_orders, purchase_orders, quote_orders, finished_products, reseller_products, part_products, assembly_products, received_invoices and issued_invoices with FK in each of the child tables to master table... This seems like a good idea but handling that with ORM brings in a little more complexity...
In this method I have a questions which FK should be used around. For example each invoice can belong to one order. Received invoice will go with Purchase order and issued invoice will go with Sale order. Should the master orders table's PK be used as a FK in the master invoices table to relate these entities, or should the child sale_orders PK be used in the child issued_invoices?
3. Concrete Table Inheritance
Having completely separated tables for every type of each entity. This would avoid me having parent->child relationship between master table but would result in a lot of similar attributes in each table...
What would be the best approach? I am aiming at ease of use in EloquentORM and also speed and scalability for the future.
I'm having trouble setting up a report model to create reports with report builder. I guess I'm doing something wrong when configuring the report model, but it might also due to change of primary entity in report builder.
I have 3 tables: Client, Address and Product. The Client has PK ClientNumber. The Address and Product both have a FK relation on ClientNumber. The relation between Client and Address is 1-to-many and also between Client and Product:
Product-(many:1)-Client-(1:many)-Address.
I've created a report model (mostly auto generate) with these 3 tables, for each table I've made an Entity.
Now on the Client Entity , I've got 2 roles, Address and Product. They both have a cardinality of 'OptionalMany', because Client can have multiple Addresses or Products. On both Address and Product I have a Client Role with cardinality 'One', because for each Address or Product, there has to be a Client (tried OptionalOne as well...).
Now I'm trying to create a report in Report Builder (2.0) where I select fields from these three entities. I'd like an overview of Clients with their main address and their products, but I don't seem to be able to create a report with fields from both Address and Products in it. I start by selecting attributes from Client, and as soon as I add Product for example the Primary entity changes as if I'm selecting Products (instead of Clients).
This is a basic example of a problem I'm facing in a much more complex model. I've tried lots of different things for 2 days, but I can't get it to work. Does anyone have an idea how to cope with this?
(Using SSRS 2008)
Edit: in T-SQL this is what i mean:
SELECT *
FROM CLIENT
INNER JOIN ADDRESS ON CLIENT.CLIENT_NUMBER = ADDRESS.CLIENT_NUMBER AND ADDRESS.TYPE = 1 --Main Address
INNER JOIN PRODUCT ON CLIENT.CLIENT_NUMBER = PRODUCT.CLIENT_NUMBER
WHERE CLIENT.CLIENT_NUMBER = 1
My experience dates back to Report Builder 1.0, but MS hasn't changed much in their report model since so it probably still applies.
As you mention, you can define many to many relations in the model, but materializing those relations in one tabular report is not possible. Once you chose one of the entities on the many side (Products), you are left without a way to bring data from the other side (Addresses).
You may have some luck with creating a "junction" table (ClientID-AddressID-ProductID) and hidding it from your users like Bob's SQL Reporting Services Blog suggests.
Ultimately this is a big limitation with MS models and it doesn't seem to improve with their latest incarnation Denali BISM many-to-many
I understand the original post is 4 years old and SSRS report models are becoming irrelevant but one solution is to define the OptionalMany relationships as OptionalOne in the model, essentially fooling the model to allow navigation and appropriate query generation.
If i want to add a record to TABLE A, is there an efficient way to add
a record in the JOIN TABLE for many (or all) records in TABLE B?
I try to build a simple task management (in CakePHP). An user adds a task and there
will be added a connection to each other user in the same group as the
current user.
At the moment, I use the find('list')-method to retrieve the IDs and
store them in a variable. But I think if the groups grow, the PHP
cache won't handle this amount of data in a single variable.
You should look into the Cake Has-And-Belongs-To-Many (HABTM) relationships. Check the cake book. It will allow you to create a relationship between two tables, using a join table, and will automatically retrieve and save values as requested in your application.
Please note, however, that from one model you cannot (by default) filter by criteria on the related model (in this case, the model related by the join table). To do this, you will need to use the Containable behavior, which will allow you to set filter criteria on the related tables.
The one other caveat is that I don't know of a way (out of the box) to add some information about the relationship in the join table. For example, if you wanted to record (in the join table) whether the user has completed the task, you would have to write your own stuff there. I usually get around this by creating a model for the join table, which I then invoke whenever I want to retrieve data specific to the joined relationship. By doing it this way, you can also easily pull up the data from the joined tables. Anybody else have a better solution?