Relational database normalization - sql

I'm having issues normalizing this table and it's really bothering me. I can see that the table is in first normal form but from there I'm stuck. My usual method is to find partial dependencies by checking for consistencies in each row in reference to a primary key. The problem with this table is both:
The first column only contains unique data and so it seems like it could be used as a primary key for the whole table. I've only ever normalized tables with a composite primary key but it seems pointless to do that here as the first column works fine as a primary key on its own.
There's no consistencies in the rows. The screens all have different movies which have different prices/dates etc. Only the customerID/customername are consistent.
I don't know if it's a proper technique but I thought about normalizing by referring to the deletion anomaly and organizing the tables so that if the session is deleted, the information about the branch is preserved. Using this I can get to something that resembles 3rd normal form but I don't think it's correct.
Session | Branch | Screen | Movie | Session | Session | Customer | Customer
ID | ID | ID | ID | Date | Price | ID | Name
SS01 | B1 | S1 | M1 | 3-May-16 | 12.50 | C1 | Chris Hemsworth
SS02 | B2 | S1 | M2 | 4-Jun-16 | 19.45 | C2 | Chris Evans
SS03 | B1 | S2 | M2 | 3-May-16 | 12.67 | C2 | Chris Evans
SS04 | B4 | S2 | M4 | 13-may-16 | 14.56 | C3 |Tom Hiddleston
SS05 | B3 | S2 | M5 | 23-may-16 | 14.56 | C2 | Chris Evans
SS06 | B3 | S1 | M5 | 3-Jun-16 | 16.32 | C1 | Chris Hemsworth
SS07 | B4 | S2 | M3 | 14-May-16 | 21.78 | C2 | Chris Evans
SS08 | B1 | S2 | M2 | 6-Jun-16 | 16.82 | C2 | Chris Evans
SS09 | B2 | S3 | M4 | 13-May-16 | 17.90 | C1 | Chris Hemsworth
SS10 | B4 | S1 | M3 | 6-Jun-16 | 16.37 | C3 | Tom Hiddleston

It looks to me like this table is in pretty good shape (assuming it's supposed to be a table describing the 'Session'). The only redundant column I see is "customer name", but everything else appears to be necessary. 'Session Price' may or may not be a calculated column (based on the other columns).
Without knowing the business logic, I can't confirm whether or not the 'branch' (or other things) needs to be in there or not.
Edit:
Hypothetically, you could remove the 'session id' column as the pk and add a compound key instead (e.g.: branch + screen + movie + session date + customer id), but that won't necessarily make it better. Instead, a uniqueness constraint on those columns may be preferred.

Related

Implementing variable sub-headers in BIRT list

How would I create variable sub-headers in a BIRT list..
The original BIRT list is as follows:
Sys_ID | Sys_Name | App_ID | App_Name
----------------------------------------
S1 | ABR | A1 | ABR: Bim
S1 | ABR | A2 | ABR: Dip
S1 | ABR | A3 | ABR: Saw
S2 | TIP | B1 | TIP: Yop
S2 | TIP | B2 | TIP: gum
S3 | GOO | C1 | GOO: res
I want to implement BIRT to show the following:
Sys_ID | Sys_Name | App_ID | App_Name
----------------------------------------
S1 | ABR | |
S1 | ABR | A1 | ABR: Bim
S1 | ABR | A2 | ABR: Dip
S1 | ABR | A3 | ABR: Saw
S2 | TIP |
S2 | TIP | B1 | TIP: Yop
S2 | TIP | B2 | TIP: gum
S3 | GOO | |
S3 | GOO | C1 | GOO: res
The Sys and App data are all implemented in one BIRT data set.
Can anyone please help?
That is easy and one of the strengths of BIRT. When you place a table on the report (or just drag-and-drop the whole dataset) you see the result as in your original list.
If you want the table to be grouped by Sys_name, you can do so. Select the table, open the properties Editor and open the Groups tab. Click add.
Select the Sys_name attribute as the Group-on parameter. (take a look at the other options, they speak for themselves)
Now click OK.
In the table you will see that two rows are added. A group header and a group footer. The group header will also include the selected group by attribute in the first column. You can change this to be any attribute that is the same for the group or something that is an aggregation of the group (like the number of elements in it).

Cast and transform generic attribute values to a flat database view

For reasons out of scope of this question I have a relation that persists generic values of an entity and looks something like this:
| group_id::int | id:int |attr_id::text | data_type::text | value::text |
-------------------------------------------------------------------------
| G1 | 1 | A | varchar | lorem |
| G1 | 1 | B | integer | 1001 |
| G2 | 2 | B | integer | 1002 |
data_type is guaranteed to be one of PostgreSQLs supported data types, so the table (or tables that is, example is simplified) somewhat represents a table definition.
I would like to present this transformed in a different view per group, so the values are cast to their actual data types. Is this even possible?
Database View for G1 Database View for G2
| id:int | A::varchar | B::int | | id:int | B::int |
-------------------------------- -------------------
| 1 | lorem | 1001 | | 2 | 1002 |
I was thinking tablefunc.crosstab would be the way to go but I didn't come very far. I'm just out of ideas. Any help or directions are very welcome.

Assign value to user hierarchy

Let's have a dimension "Category" defined with the following table :
ID | CategoryLevel1 | CategoryLevel2 | CategoryLevel3
---|----------------|----------------|---------------
1 | C1 | C11 | C111
2 | C1 | C11 | C112
3 | C1 | C11 | C113
4 | C1 | C12 | C121
5 | C1 | C12 | C122
6 | C1 | C12 | C123
7 | C2 | C21 | C211
...| ... | ... | ...
and a fact defined with the table :
CategoryID | Value
-----------|---------
1 | v1
2 | v2
3 | v3
4 | v4
5 | v5
... | ...
In SSAS we defined a user-hierarchy as :
CategoryLevel3 --> CategoryLevel2 --> CategoryLevel1
We notice that CategoryLevel3 determines the granularity of the fact table.
Suppose the fact table shouldn't be rolled up by summing (for example : number of customers for category at level 3) but instead, we have to set data for higher levels in hierarchy (CategoryLevel2 and CategoryLevel1).
Is it possible to do that in SSAS with a minimum of change in dimension table (because it's used with many other fact table).
Thanks,
It is possible to have multiple measure groups loaded at different granularity level of dimensions for the same type of facts.
Then by using scope statements, you can retrieve data from corresponding measure groups.

sql - How do I implement a table where few attributes are just references to another tuple?

I have a Sql table, shown below:-
> select * from table1;
|--------------------------------------------------|
| ID | A1 | A2 | B1 | B2 | C1 | C2 | REF_B | REF_C |
|--------------------------------------------------|
| 1 | a1 | a1 | b1 | b1| c1 | c1 | 1 | 1 |
| 2 | a2 | a2 | b2 | b2| c1 | c1 | 2 | 1 |
| 3 | a3 | a3 | b1 | b1| c1 | c1 | 1 | 1 |
|--------------------------------------------------|
ID is Primary key.
A1 and A2 are unique to each tuple.
B1 and B2 are the values of tuple pointed to by REF_B attribute of the current row.
C1 and C2 are the values of tuple pointed to by REF_C attribute of the current row.
REF_B refers to the ID of another tuple in this same table from where we should get the values of Bx.
REF_C refers to the ID of another tuple in this same table from where we should get the values of Cx.
In this the above approach the obvious problem we face is propagating the changes made in tuple 1 to tuples 2 and 3. Right now we have used programmatic approach (Java code) to achieve this.
This is both difficult and not beautiful.
Proposed change
Divide table1 into three tables.
> select * from table1_a;
|------------------------------|
| ID | A1 | A2 | REF_B | REF_C |
|------------------------------|
| 1 | a1 | a1 | 1 | 1 |
| 2 | a2 | a2 | 2 | 1 |
| 3 | a3 | a3 | 1 | 1 |
|------------------------------|
> select * from table1_b;
|--------------|
| ID | B1 | B2 |
|--------------|
| 1 | b1 | b1 |
| 2 | b2 | b2 |
|--------------|
> select * from table1_c;
|--------------|
| ID | C1 | C2 |
|--------------|
| 1 | c1 | c1 |
|--------------|
table1 will be a updatable view over the join of these three tables.
Do you see any possible flaw in this approach?
Is there an easier solution?
What are the possible restrictions we may have on the new table1. table1 directly maps to an ADF Entity Object.
Use a trigger:
CREATE OR REPLACE TRIGGER upd_table1
BEFORE UPDATE OF a1
OR UPDATE OF a2
ON TABLE1
REFERENCING new AS new
BEGIN
UPDATE table1
SET b1 = new.a1, b2 = new.a2
WHERE refb = new.id;
UPDATE table1
SET c1 = new.a1, c2 = new.a2
WHERE refc = new.id;
END;
It sounds like your proposed solution is a normalization of your original table, assuming you make REF_A & REF_B (though I'd name these A_ID and B_ID, myself) foreign keys to table1_b and table1_c. Is that what you have in mind?
One thing that's not clear to me is why you need two columns here (A1 & A2) if they contain the same data. Couldn't you consolidate that into a single column and then simply select twice if you need two copies in the result? ie, assuming you had only one "A" column instead of A1/A2:
select A, A from table1....
But, I might be missing the intended use case here.
I've never used ADF, but the oracle documentation seems to imply you can reference a view:
Entity objects map to single objects in the datasource. In the vast majority of cases, these >are tables, views, synonyms, or snapshots in a database.
If this isn't very helpful, perhaps add some detail concerning the underlying purpose of this table.

How can I display two rows worth of data on one line side-by-side in Report Designer?

I am using SQL Server Reporting Services 2005, and I'm developing a report in Report Designer/Business Intelligence Studio. Right now I have a normal-looking table that displays data like this:
----------------
| A | B | C |
----------------
| A1 | B1 | C1 |
----------------
| A2 | B2 | C2 |
----------------
| A3 | B3 | C3 |
----------------
What I would like to do, is display two rows side-by-side on the same line, so that the table would look like this:
-------------------------------
| A | B | C | A | B | C |
-------------------------------
| A1 | B1 | C1 | A2 | B2 | C2 |
-------------------------------
| A3 | B3 | C3 | A4 | B4 | C4 |
-------------------------------
Is this even possible? Does anyone know how to accomplish this? Google searches have turned up nothing for me so far. Thanks in advance for any help.
Ok, I figured out how to do what I wanted. I created a table with 2 (repeating) table detail rows, with the following values:
--------------------------------------------------------------------------------------------------------------------------------------------
| =Previous(Fields!A.Value) | =Previous(Fields!B.Value) | =Previous(Fields!C.Value) | = Fields!A.Value | =Fields!B.Value | =Fields!C.Value |
--------------------------------------------------------------------------------------------------------------------------------------------
| =Fields!A.Value | =Fields!B.Value | =Fields!C.Value | | | |
--------------------------------------------------------------------------------------------------------------------------------------------
Then I went to the properties of each row, and set the "hidden" value to an expression. For the first line I used this expression:
=Iif(RowNumber("table1") mod 2 = 0, false, true)
For the second line, I used this expression:
=Iif(RowNumber("table1") = CountRows("table1") AND RowNumber("table1") mod 2 = 1, false, true)
That did the trick. It now displays how I wanted.
You would need a matrix report.
eidt: although now that I think about it that would probably only be able to get you to something like this:
| A1 | B1 | C1 |
-------------------------------------------------------
| A | B | C | A | B | C | A | B | C |
Would that format work for you?