One to many Relationship in SQL Server Analysis Services - sql-server

I have these tables:
DimDate (PK: DateKey, other attributes)
FactActivationCodes (PK: ActivationCode, IssuedDateKey (FK to DimDate)
FactExpirations (PK: ActivationCode + ExpirationType, FK: ActivationCode to FactActivationCodes)
I set up measures that count the number of rows in
Issued Count (count of rows in FactActivationCodes)
Expired Count (count of distinct ActivationCodes in FactExpirations)
The idea is that the FactActivationCodes has one activation code, with a date when it was issued. The activation code can get expired year after year (and then renewed) so it would have a row for expiration in FactExpirations (one each year)
I put some test rows in the tables; I put 3 rows in FactActivationCodes (different IssuedDate for each) , and only 2 in FactExpirations. When I browse the cube, and I am looking at the count of Issued on columns, and the Issued Date (dimension) on rows, it looks like this:
Issued Date
January 2008 1
February 2008 1
March 2008 1
But then, when I add the Expired Count, I was hoping to see the 'expired column' count with only the ones that match the 'Activation Code' like so, because of the one to many relationship between the two fact tables:
Issued Date Expired Date
January 2008 1 1
February 2008 1 1
March 2008 1 0
But instead, I a cross join of everything like so, with the totals of expired:
Issued Date Expired Date
January 2008 1 2
February 2008 1 2
March 2008 1 2
April 2008 2
May 2008 2
June 2008 2
And onwards, for every date entry in my Date Dimensions... I guess I'm not doing the relationship correctly... how can I get the expected result?

The answer to use referenced relationship: http://technet.microsoft.com/en-us/library/ms166704.aspx

Related

In SQL Server, how do I get the date of an event from a table and the date the previous event happened?

I'm using Microsoft SQL Server 2016 (SP2) (13.0.5026.0 (X64). I have a query that joins a people table with a contacts table. The people table has the client detail and the contacts table tells us the last time that client has made a contact.
The below query links the tables and gives me the client ID and the date they made contact
SELECT
DP.dim_person_ID AS [Dim_Person_ID],
CAST(FC.CONTACT_DTTM AS date) AS [Contact Date]
FROM
Child_Social.Fact_Contacts FC
INNER JOIN
CHILD_SOCIAL.DIM_Person DP ON FC.dim_person_ID = DP.Dim_Person_ID
If they made multiple contacts they will return a row for each one and the output will look like this
Person_ID
Contact Date
1
01/01/2023
1
01/10/2022
1
01/07/2022
1
01/04/2022
1
01/01/2022
2
02/01/2023
2
02/10/2022
2
02/07/2022
2
02/04/2022
2
02/01/2022
What I'm trying to do is to add a column to the query that shows the previous contact date as well eg return an output like
Person ID
Contact Date
Previous Contact Date
1
01/10/2022
01/07/2022
1
01/07/2022
01/04/2022
2
02/10/2022
02/07/2022
2
02/07/2022
02/04/2022
I'm unsure how to create a join/sub query that will calculate a previous episode (rather than a most recent episode or a first episode, just the previous one).
Any help or guidance gratefully received

Google Data Studio Table: Dividing Data that has 2 different Years

I need to produce a table that has Quotes win%. The formula is #won divide by #sent.
My problem is, there are quotes that are won within a year but were sent in different years.
(My data comes from BigQuery)
The data looks like this:
Sale Sent Won
sale1 2019 2020
sale2 2019 2020
sale3 2016 2017
sale4 2017 2019
sale5 2020 2020
sale6 2020 2020
sale7 2018 2018
sale8 2016 2016
sale9 2015 2016
sale10 2016 2017
sale11 2016 2018
sale12 2018 2019
I'd like to be able to create a table in data studio like this:
Year SENT WON WIN%
2016 4 2 50%
2017 1 2 200%
2018 2 2 100%
2019 2 2 100%
2020 2 4 200%
I would love to see if this is possible in google data studio. Any suggestion is highly appreciated.
Added a Google Data Studio Report to demonstrate, as well as a GIF showing the process below.
One approach is to restructure the Data at the Data Set and use Calculated Fields in a Table:
1) Data Transformation
The data needs to be transformed from the current Wide structure to a Long data structure. One way it can be achieved in Google Sheets is by using the formula below (Sheet1 represents the input sheet; consult embedded Google Sheet for clarification):
=ArrayFormula(QUERY({
{Sheet1!A:A,IF(LEN(Sheet1!A:A),"Sent",""),Sheet1!B:B};
{Sheet1!A:A,IF(LEN(Sheet1!A:A),"Won",""),Sheet1!C:C}
},"Select * Where Col3 is not null Label Col2 'Dimension', Col3 'Year'",1))
2) Table
- Dimension: Year
- Sort: Year in Ascending order
- Metrics: Add the 3 calculated fields below:
3) Calculated Fields
The formulas below create the metrics used in the Table above (Formula 3.1 and 3.2 need to be added at the Data Source-level, while 3.3 can be added at the Chart-level if required):
3.1) SENT
COUNT(CASE
WHEN REGEXP_MATCH(Dimension, "Sent") THEN Year
ELSE NULL END)
3.2) WON
COUNT(CASE
WHEN REGEXP_MATCH(Dimension, "Won") THEN Year
ELSE NULL END)
3.3) WIN%
WON / SENT

SQL Server - Slowly Changing dimension join

I have a fact table and employee "tier" table, let's say.
So the fact table looks sorta like
employee_id call date
Mark 1 1-1-2017
Mark 2 1-2-2017
John 3 1-2-2017
Then there needs to be a data structure for 'tier level' - a slowly changing dimension table. I want to keep this simple -- I can change the structure of this table to whatever, but for now I've created it as such.
employee_id tier1_start ... tier2_start ... tier3_start
Mark 5-1-2016
John 6-1-2016 8-1-2016
Lucy 6-1-2016 10-1-2016
Two important notes. This table sort of operates under the assumption that a promotion will only occur once - aka no demotions and repromotions will occur. Also, it's possible one can jump from tier 1 to tier 3.
I was trying to come up with the best possible query for coming up with a 'tier' dimension (denormalization) for the fact table.
For instance, I want to see the Tier 1 metrics for February, or the Tier 2 metrics for February. Obviously the historically-changing tier dimension must be linked.
The clumsiest way I can think of doing this for now ... is simply joining the fact table on the tier table using employee_id.
Then, doing an even clumsier case statement:
case
when isnull(tier3_start,'0') < date then 'T3'
when isnull(tier2_start, '0') < date then 'T2'
when isnull(tier1_start, '0') < date then 'T1'
else 'other'
end as tier_level
Yes, as you can see this is very clumsy.
I'm thinking maybe I need to change the structure of this a bit.
You're probably better off splitting your tier table in two.
So have a Tier table like this:
TierID Tier
------------------
1 Tier 1
2 Tier 2
3 Tier 3
And an EmployeeTier table:
ID EmpID TierID TierDate
---------------------------------------
1 1 1 Jun 1, 2016
2 1 3 Oct 2, 2016
3 2 1 Jul 10, 2016
4 2 2 Nov 11, 2016
Now you can query the EmployeeTier table and filter on the TierID you're looking for.
This also gives you the ability to promote/demote multiple times. You simply filter by the employee and sort by date to find the current tier.

Pivot or unpivot a table

I have a table in SQL that I need to pivot or unpivot (not sure which). The table consists of days (as represented by workdays##1, workdays##2, workdays##3,etc.) The values under these days are a business day value for the month. Other columns in this table are Company, Year, Monthnum which should remain as columns. So it looks something like this:
SQL table
Company Year Monthnum workday##1 workday##2 workday##3 workday##4
US 2016 8 1 2 3 4
I need the workday##'s (renamed as day of month and substringed to just the number portion) to pivot to rows and the values under them to be put in one column with the header businessday. Future
Company Year Monthnum Dayofmonth Businessday
US 2016 8 1 (workday##1) 1
US 2016 8 2 (workday##2) 2
US 2016 8 3 (workday##3) 3
US 2016 8 4 (workday##4) 4
This table represents the year and month and the number of business days per month. From this I will be doing some month to date calculations against sales goals on a daily basis.

Join two tables depending on date sequence

In SQL Server 2008, I want to join two tables depending on date sequence. More specifically, I need to left join Payments table to Profiles table by the following rules:
UserId has to be matched.
Every record in Payments matches the record in Profiles with the closest Profiles.CreationDate before Payments.PayDate.
For a simplified example,
Table Payments:
UserId PayDate Amount
1 2012 400
1 2010 500
2 2014 600
Table Profiles:
UserId CreationDate Address
1 2009 NY
1 2015 MD
2 2007 NJ
2 2013 MA
3 2008 TX
Desired Result:
UserId CreationDate PayDate Amount Address
1 2009 2010 500 NY
1 2009 2012 400 NY
2 2013 2014 600 MA
It's guaranteed that a user have at least 1 Profiles record before he pays. Another restriction is that I not authorized to write anything into the database.
I idea is first left join Payments with Profiles, then within the record group matching each (UserId, PayDate) tuple, sort it by CreationDate, then select the last record. But I don't know how to implement it in SQL language, or are there any better ways to do this merge?
Use Outer Apply to do this.
SELECT py.UserId,
CreationDate,
PayDate,
Amount,
Address
FROM Payments py
OUTER APPLY (SELECT TOP 1 *
FROM Profiles pr
WHERE py.UserId = pr.UserId
and PayDate> CreationDate
ORDER BY CreationDate desc) cs
SQLFIDDLE DEMO

Resources