User defined calendar table in power bi - calendar

I am trying to add calendar table in power bi .. here how i add
Calender = ADDCOLUMNS(CALENDAR (DATE(1995,5,1), DATE(2019,12,31)),
"Year",FORMAT([Date],"YYYY"),"Quarter","Q" &FORMAT([Date],"Q"),
"Month",FORMAT([Date],"MM"),"MonthName",FORMAT([Date],"MMM"),"Monthnumber", FORMAT ([Date], "MM" ),
"YearMonthnumber", FORMAT ( [Date], "YYYY/MM" ),
"YearMonthShort", FORMAT ( [Date], "YYYY/mmm" ),
"MonthNameShort", FORMAT ( [Date], "mmm" ),
"MonthNameLong", FORMAT ( [Date], "mmmm" ),
"DayOfWeekNumber", WEEKDAY ( [Date] ),
"DayOfWeek",FORMAT ( [Date], "dddd" ),
"DayOfWeekShort", FORMAT ( [Date], "ddd" ),
"YearQuarter", FORMAT ( [Date], "YYYY" ) & "/Q" & FORMAT ( [Date], "Q" ))
check this picture
and these are more tables
now i want to ask how i add and link datekey in orders_Fact table where there is no column of datekey in fact table.. i manually create it by query .. when i click on edit queries from home tab then i did not find calendar table in this panel
this is the file link
https://www.dropbox.com/s/tdsf0xhogr4opgr/test_fle.pbix?dl=0

Your calendar table is created by DAX and indeed is not visible in "edit query" view.
I would check if the calendar is on the right of the relationship view of the Power Query Editor (scroll right)
Otherwise try to create the relationship between OrderDate of the facts table & Date in calendar table with the "manage relationship" in ribbons pane.

Related

How do I dynamically generate dates between two dates in Snowflake?

I've been searching for a good generate_series analog in Snowflake but what I've found so far is a bit limiting in scope. Most of the examples I've seen use rowcount but I need something more dynamic than that.
I have these columns:
location_id, subscription_id, start_date, end_date
The datediff of the date columns is usually a year but there are many instances where it isn't so I need to account for that.
How do I generate a gapless date range between my start and end dates?
Thank you!
There are several ways to approach this, but here's the way I do it with SQL Generator function Datespine_Groups.
The reason I like to do it this way, is because its flexible enough that I can add weekly, hourly, or monthly intervals between the dates and reuse the code.
The parameter group bounds changes the way the join happens in a subtle way that allows you to control how the dates get filtered out:
global - every location_id, subscription_id combination will start on the same start_date
local - every location_id, subscription_id has their own start/end dates based on the first and last values in the date column
mixed - every location_id, subscription_id has their own start/end dates, but they all share the same end date
Rather than try and make it perfect in 1 query, I think it's probably easier to generate it with mixed and then filter out where the group_start_date occurs after the end_date of your original data.
Here's the SQL. At the very beginning you can either (1) find a way to dynamically generate the 3 parameters, or (2) hard code a ridiculous range that'll last your career and let the rest of the query filter them out :)
You can change month to another datepart, I only assumed you were looking for monthly.
WITH GLOBAL_SPINE AS (
SELECT
ROW_NUMBER() OVER (
ORDER BY
NULL
) as INTERVAL_ID,
DATEADD(
'month',
(INTERVAL_ID - 1),
'2018-01-01T00:00' :: timestamp_ntz
) as SPINE_START,
DATEADD(
'month', INTERVAL_ID, '2018-01-01T00:00' :: timestamp_ntz
) as SPINE_END
FROM
TABLE (
GENERATOR(ROWCOUNT => 2192)
)
),
GROUPS AS (
SELECT
location_id,
subscription_id,
MIN(start_date) AS LOCAL_START,
MAX(start_date) AS LOCAL_END
FROM
My_First_Table
GROUP BY
location_id,
subscription_id
),
GROUP_SPINE AS (
SELECT
location_id,
subscription_id,
SPINE_START AS GROUP_START,
SPINE_END AS GROUP_END
FROM
GROUPS G CROSS
JOIN LATERAL (
SELECT
SPINE_START,
SPINE_END
FROM
GLOBAL_SPINE S
WHERE
S.SPINE_START >= G.LOCAL_START
)
)
SELECT
G.location_id AS GROUP_BY_location_id,
G.subscription_id AS GROUP_BY_subscription_id,
GROUP_START,
GROUP_END,
T.*
FROM
GROUP_SPINE G
LEFT JOIN My_First_Table T ON start_date >= G.GROUP_START
AND start_date < G.GROUP_END
AND G.location_id = T.location_id
AND G.subscription_id = T.subscription_id

Can we partition an oracle database based on two columns

I am working for a new project that require to partition the table based on two columns (city and area). does oracle database support that ?
I worked on projects before where I partition the database based on one column when creating the table. but I have no idea on how to partition using two columns do we use the same semantic or different one
CREATE TABLE TEST (....)
PARTITION BY RANGE (date1) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION TEST_INITIAL VALUES less than (DATE '2000-01-01')
);
If you have Oracle 12.2 or later, this is a snap. Use AUTOMATIC partitioning. E.g.,
CREATE TABLE my_auto_partitioned_table
( id NUMBER,
city_name VARCHAR2(80),
area_name VARCHAR2(80),
other_data VARCHAR2(400) )
PARTITION BY LIST ( city_name, area_name) AUTOMATIC
( PARTITION p_dummy VALUES (null, null) )
;
Pre 12.2, it is possible, with LIST-LIST partitioning, but it is a real pain because you have to pre-create all your partitions and subpartitions. E.g.,
CREATE TABLE my_partitioned_table
( id NUMBER,
city_name VARCHAR2(80),
area_name VARCHAR2(80),
other_data VARCHAR2(400) )
PARTITION BY LIST ( city_name )
SUBPARTITION BY LIST ( area_name )
-- if your area names are generic (e.g., "north"/"south" or "downtown"/"suburbs"),
-- you can use a SUBPARTITION TEMPLATE clause right here...
( PARTITION p_philadelpha VALUES ( 'PHILADELPHIA')
( SUBPARTITION p_philly1 VALUES ('SOUTH PHILLY','WEST PHILLY'),
SUBPARTITION p_philly2 VALUES ('NORTH PHILLY','OLD CITY')
),
PARTITION p_new_york VALUES ( 'NEW YORK')
( SUBPARTITION p_nyc1 VALUES ('SOHO'),
SUBPARTITION p_nyc2 VALUES ('HELL''S KITCHEN')
)
);
I would not do that. It is the same if somebody would ask: I like to partition my table by Months and Day of a date column. Just define the partition by Day, then you are done.
Anyway, in general you can use several columns if you define a virtual column and partition on that:
CREATE TABLE my_auto_partitioned_table
( id NUMBER,
city_name VARCHAR2(80),
area_name VARCHAR2(80),
partition_key VARCHAR2(200) GENERATED ALWAYS AS (city_name||-||area_name) VIRTUAL)
PARTITION BY LIST ( partition_key ) ...
But I don't think this would make so much sense in your case.

SQL to identify initial dates for a product that changes from active to cancelled status

I have a table that records the following items:
product_id
product_status
date
Products can exist in the following product statuses: pending, active, or canceled. Only one status can exist per date per product code. A status and product code is inserted for each and every day a product exists.
Utilizing SQL I'd like to be able to identify the initial cancellation dates for a product that cancels more than once in a given time frame.
i.e. if a product is active for 3 days and then cancels for 3 days and then is active again for 3 days and then cancels again for another 3 days.
I'd like to be able to identify day 1 of the 2 cancellation periods.
Thought I'd get the crystal ball out for this one. This sounds like a Gaps and Islands question. There's plenty of answers on how to do this on the internet, however, this might be what you're after:
CREATE TABLE #Sample (product_id int,
product_status varchar(10),
[date] date); --blargh
INSERT INTO #Sample
VALUES (1,'active', '20170101'),
(1,'active', '20170102'),
(1,'active', '20170103'),
(1,'cancelled', '20170104'),
(1,'cancelled', '20170105'),
(1,'cancelled', '20170106'),
(1,'active', '20170107'),
(1,'pending', '20170108'),
(1,'active', '20170109'),
(1,'cancelled', '20170110'),
(2,'pending', '20170101'),
(2,'active', '20170102'),
(2,'cancelled', '20170103'),
(2,'cancelled', '20170104');
GO
SELECT *
FROM #Sample;
WITH Groups AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY product_id
ORDER BY [date]) -
ROW_NUMBER() OVER (PARTITION BY product_id, product_status
ORDER BY [date]) AS Grp
FROM #Sample)
SELECT product_id, MIN([date]) AS cancellation_start
FROM Groups
WHERE product_status = 'cancelled'
GROUP BY Grp, product_id
ORDER BY product_id, cancellation_start;
GO
DROP TABLE #Sample;
If not, then see Patrick Artnet's comment.

Power BI Filter By Multiple Criteria using "AND"

Background
I've got a database that stores employees and their skills. What I want to do is be able to use a slicer to select multiple skills and show the employees that have ALL of the skills selected.
Problem
When I select multiple criteria, and "OR" is applied, showing me employees that have any of the skills selected. (See screenshot)
Question
In the example above, how do I modify my report so that only Steve shows up?
What I've Tried
I've added a new measure based on the DAX that Tab Alleman has proposed, but I'm still seeing "OR" logic being implemented. Here's the DAX:
Employees with all skills =
COUNTROWS (
FILTER (
ADDCOLUMNS (
VALUES ('dw Employee'[ADUserId]),
"Skills",
CALCULATE (
COUNTROWS ( VALUES ( 'dw Skill'[SkillName] ) ),
CALCULATETABLE ( 'dw EmployeeSkill' )
)
),
[Skills] = COUNTROWS ( VALUES ( 'dw Skill'[SkillName] ) )
)
)
The measure Employees with all skills measure is fundamentally correct, but does not behave in the way you expect.
It is a measure, so by itself, it does not change how a table is filtered unless the measure is used in the table (either by adding the measure to the table as a column or by using the measure as a filter).
If you create a table with just Employee[Full Name] and your measure, you will see only Steve appear.
Since you don't want the measure to appear, you can also put it in the Visual Level Filter and get the same effect:
However, one tricky part of what you're doing is that you want to display the skill name too. As soon as you drag Skill Name onto the table, Joshua, Eric & other employees with either skill are going to reappear (because it messes with the row counts that the measure relies upon).
To address this, the measure you're using needs to be updated to ignore the Skill Name when calculating row counts:
Employees with all skills =
CALCULATE (
COUNTROWS (
FILTER (
ADDCOLUMNS (
VALUES ( 'dw Employee'[ADUserId] ),
"Skills", CALCULATE (
COUNTROWS ( VALUES ( 'dw Skill'[SkillName] ) ),
CALCULATETABLE ( 'dw EmployeeSkill' )
)
),
[Skills] = COUNTROWS ( ALLSELECTED( 'dw Skill'[SkillName] ) )
)
),
ALLSELECTED ( 'dw Skill'[SkillName] )
)
All that I've really changed is the first and last lines. I've wrapped the entire measure in a new CALCULATE statement, and then at the very end changed the filter context to include all SkillNames from the 'dw Skill' table.
This then allows you to create a table with both FullName and SkillName and still only get Steve back:
Note: I don't claim my DAX modification above is the most efficient or best solution to this problem.

SQL Server: table design for changing Identity records

I have a view which displays test data from multiple sources for a GPS spot.
The view displays the "GPS Point ID" and some geological test results associated with this GPS Point.
The GPS-POINT-ID is like this : XYZ-0XX-CCCCC
XYZ : Area
00XX : ID
CCCC: Coordinates
The GPS point name changes over time, the first portion of point name(XYZ-0XX) is same and doesn't change, but the Coordinate part (CCCC) changes according to new GPS point location.
I wanted to design a table that will have the previously mentioned view as a datasource. I need to decide about the following:
Primary key: if I used the full GPS-POINT-ID, I won't be able to keep track of the changes because it changes frequently over time. I can't keep track of the point. and I can't link it to it's historical records.
If I use the fixed part of GPS-Point-ID (XYZ-00XX) as a computed column, I can't use it as a primary key, because the same point has many historical records that have the same (XYZ-00XX) part, this will violate the primary key duplicate constraint.
If I create an identity column that will increase for each new record, how can I keep track of each point name change and get the latest test data as well as historical data for each point (XYZ-00XX).
Sample rows from the view are attached in a snapshot.
Thanks
I would recommend using identity for primary key with no business value. I would store the data in two columns one with the static data and another with the changing data. Then you can have a computed column that puts them together as one field if that is necessary. You can also add a date field so that you can follow the history. The static data column being the identifier that ties the records together.
I am assuming you do not want to use auditing to track historical records for some reason. That is the approach I would normally take.
http://weblogs.asp.net/jongalloway/adding-simple-trigger-based-auditing-to-your-sql-server-database
EDIT:
Sample query works if only one update can happen on a given date. If more than one update can occur then the row_number function can be used instead of group by.
Select *
From Table T1
Join (Select Max(MatchDate) MatchDate, GpsStaticData
From Table Group By GpsStaticData) T2
On T1.GpsStaticData = T2.GpsStaticData And T1.UpdateDate = T2.MatchDate
EDIT:
Using Row_Number()
With cteGetLatest As
(
Select UpdateDate MatchDate, GpsStaticData,
Row_Number() Over (Partition By GpsStaticData, Order By UpdateDate Desc) SortOrder
)
Select *
From Table T1
Join (Select MMatchDate, GpsStaticData
From cteGetLatest Where SortOrder = 1) T2
On T1.GpsStaticData = T2.GpsStaticData And T1.UpdateDate = T2.MatchDate
You can add more fields after Order By UpdateDate in the row_number function to determine which record is selected.
--To avoid artificial columns overhead costs a compound Primary Key can be used:
-- Simulate the Source View
CREATE TABLE ybSourceView (
[GPS-POINT-ID] VARCHAR(20),
[Status] NVARCHAR(MAX),
UpdateDate [datetime2],
Reason NVARCHAR(MAX),
OpId VARCHAR(15)
);
-- Source View sample data
INSERT INTO ybSourceView ([GPS-POINT-ID], [Status], UpdateDate, Reason, OpId)
VALUES ('RF-0014-9876', 'Reachable' , '2015-01-27 13:36', 'New Updated Coordinate' , 'AFERNANDO'),
('RF-0014-9876', 'Reachable' , '2014-02-27 09:37', 'New Updated Coordinate' , 'AFERNANDO'),
('RF-0014-3465', 'Reachable' , '2015-04-27 09:42', 'New Updated Coordinate' , 'HRONAULD' ),
('RF-0014-2432', 'Reachable' , '2013-06-27 12:00', 'New Updated Coordinate' , 'AFERNANDO'),
('RF-0015-9876', 'OUT_OF_Range', '2014-04-14 12:00', 'Point Abandoned, getting new coordinate', 'AFERNANDO');
-- Historic Data Table
CREATE TABLE ybGPSPointHistory (
Area VARCHAR(5) NOT NULL DEFAULT '',
ID VARCHAR(10) NOT NULL DEFAULT '',
Coordinates VARCHAR(20) NOT NULL DEFAULT '',
[GPS-POINT-ID] VARCHAR(20),
[Status] NVARCHAR(MAX),
UpdateDate [datetime2] NOT NULL DEFAULT SYSUTCDATETIME(),
Reason NVARCHAR(MAX),
OpId VARCHAR(15),
CONSTRAINT ybGPSPointHistoryPK PRIMARY KEY (Area, ID, UpdateDate) --< Compound Primary Key
);
GO
-- Update Historic Data Table from the Source View
INSERT INTO ybGPSPointHistory (Area, ID, Coordinates, [GPS-POINT-ID], [Status], UpdateDate, Reason, OpId)
SELECT LEFT(Src.[GPS-POINT-ID], LEN(Src.[GPS-POINT-ID]) - 10), RIGHT(LEFT(Src.[GPS-POINT-ID], LEN(Src.[GPS-POINT-ID]) - 5), 4), RIGHT(Src.[GPS-POINT-ID], 4), Src.[GPS-POINT-ID], Src.[Status], Src.UpdateDate, Src.Reason, Src.OpId
FROM ybSourceView Src
LEFT JOIN ybGPSPointHistory Tgt ON Tgt.[GPS-POINT-ID] = Src.[GPS-POINT-ID] AND Tgt.UpdateDate = Src.UpdateDate
WHERE Tgt.[GPS-POINT-ID] Is NULL;
--Tests (check Actual Execution Plan to see PK use):
-- Full history
SELECT * FROM ybGPSPointHistory;
-- Up-to-date only
SELECT *
FROM (
SELECT *, RANK () OVER (PARTITION BY Area, ID ORDER BY UpdateDate DESC) As HistoricOrder
FROM ybGPSPointHistory
) a
WHERE HistoricOrder = 1;
-- Latest record for a particular ID
SELECT TOP 1 *
FROM ybGPSPointHistory a
WHERE [GPS-POINT-ID] = 'RF-0014-9876'
ORDER BY UpdateDate DESC;
-- Latest record for a particular ID in details (more efficient)
SELECT TOP 1 *
FROM ybGPSPointHistory a
WHERE Area = 'RF' AND ID = '0014' AND Coordinates = '9876'
ORDER BY UpdateDate DESC;
-- Latest record for a particular point
SELECT TOP 1 *
FROM ybGPSPointHistory a
WHERE Area = 'RF' AND ID = '0014'
ORDER BY UpdateDate DESC;
--Clean-up:
DROP TABLE ybGPSPointHistory;
DROP TABLE ybSourceView;

Resources