Zeittabelle Archive | THE SELF-SERVICE-BI BLOG Wir lieben Microsoft Power BI Mon, 14 Apr 2025 07:08:33 +0000 de hourly 1 https://wordpress.org/?v=6.8.1 https://ssbi-blog.de/wp-content/uploads/2019/10/Favicon-150x150.png Zeittabelle Archive | THE SELF-SERVICE-BI BLOG 32 32 Meine projekterprobte Zeittabelle für Power BI und Power Pivot https://ssbi-blog.de/blog/business-topics/meine-projekterprobte-zeittabelle-fuer-power-bi-und-power-pivot/ Tue, 13 Jul 2021 14:22:25 +0000 https://ssbi-blog.de/?p=9916 In meinem letzten Beitrag habe ich über die Erstellung einer praxiserprobten Kalendertabelle geschrieben. Dies ist für nahezu jedes BI-Projekt relevant. Deutlich seltener werden meiner Erfahrung nach Analysen auf Basis der Uhrzeit vorgenommen. Auch hierfür habe ich eine Zeittabelle entworfen, die ich Dir in diesem Beitrag zur Verfügung stellen möchte. Als Abonnent meines Newsletters erhältst Du […]

Der Beitrag Meine projekterprobte Zeittabelle für Power BI und Power Pivot erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
In meinem letzten Beitrag habe ich über die Erstellung einer praxiserprobten Kalendertabelle geschrieben. Dies ist für nahezu jedes BI-Projekt relevant. Deutlich seltener werden meiner Erfahrung nach Analysen auf Basis der Uhrzeit vorgenommen. Auch hierfür habe ich eine Zeittabelle entworfen, die ich Dir in diesem Beitrag zur Verfügung stellen möchte.

Als Abonnent meines Newsletters erhältst Du die Beispieldateien zu den Beiträgen dazu. Hier geht’s zum Abonnement des Newsletters!

Warum überhaupt eine separate Zeittabelle?

Die DAX Time-Intelligence-Funktionen machen es notwendig, dass eine Kalendertabelle genau eine Zeile pro Kalendertag aufweist. Es ist daher nicht möglich, eine Kalendertabelle auf Stundenebene, oder gar noch granularer zu gestalten. Sollten Dich dazu mehr Details interessieren, wirst Du in diesem meiner Artikel fündig.

Meine Zeittabellenfunktion

Wie auch bei meiner Kalendertabellenfunktion, mag ich es, wiederkehrende Power Query-Aufgaben in M-Funktionen zu kapseln. Hier ist meine Zeittabellenfunktion:

let
fn = (Zeiteinheit, optional StundenSegment, optional MinutenSegment, optional SekundenSegment) as table =>
let
/*
Zeiteinheit = "Sekunde", //Minute, Sekunde
StundenSegment = 2,
MinutenSegment = 15,
SekundenSegment = 30,
*/
Start = #datetime(1900, 1, 1, 0, 0, 0),
//Zeit-Segmente anpassen
StdSeg = if StundenSegment = null then null else StundenSegment,
MinSeg = if MinutenSegment = null then null else MinutenSegment,
SekSeg = if SekundenSegment = null then null else SekundenSegment,
Increment =
if Zeiteinheit = "Stunde" then
[Duration = #duration(0, 1, 0, 0), CountFactor = 24]
else if Zeiteinheit = "Minute" then
[Duration = #duration(0, 0, 1, 0), CountFactor = 24 * 60]
else
[Duration = #duration(0, 0, 0, 1), CountFactor = 24 * 60 * 60],
ListOfTimes = List.DateTimes(Start, Increment[CountFactor], Increment[Duration]),
ColumnsOfTimes = Table.FromList(
ListOfTimes,
Splitter.SplitByNothing(),
null,
null,
ExtraValues.Error
),
#"Geänderter Typ" = Table.TransformColumnTypes(
ColumnsOfTimes,
{{"Column1", type time}}
),
#"Umbenannte Spalten" = Table.RenameColumns(#"Geänderter Typ", {{"Column1", "Zeit"}}),
GetTableOfTimeComponents = Table.AddColumn(#"Umbenannte Spalten", "Benutzerdefiniert", each
if Zeiteinheit = "Stunde" then
Table.FromRecords(
{
[
Stunde = Text.PadStart(Text.From(Time.Hour([Zeit])), 2, "0"),
#"Stunde #" = Number.From(Stunde)
]
},
type table [Stunde = Text.Type, #"Stunde #" = number]
)
else
if Zeiteinheit = "Minute" then
Table.FromRecords(
{
[
Stunde = Text.PadStart(Text.From(Time.Hour([Zeit])), 2, "0"),
Minute = Text.PadStart(Text.From(Time.Minute([Zeit])), 2, "0"),
S_M = Stunde &":"& Minute,
#"Stunde #" = Number.From(Stunde),
#"Minute #" = Number.From(Minute)
]
},
type table [Stunde = Text.Type, Minute = Text.Type, S_M = Text.Type, #"Stunde #" = number, #"Minute #" = number]
)
else
Table.FromRecords(
{
[
Stunde = Text.PadStart(Text.From(Time.Hour([Zeit])), 2, "0"),
Minute = Text.PadStart(Text.From(Time.Minute([Zeit])), 2, "0"),
Sekunde = Text.PadStart(Text.From(Time.Second([Zeit])), 2, "0"),
S_M = Stunde &":"& Minute,
S_M_S = Stunde &":"& Minute &":"& Sekunde,
#"Stunde #" = Number.From(Stunde),
#"Minute #" = Number.From(Minute),
#"Sekunde #" =Number.From(Sekunde)
]
},
type table [Stunde = Text.Type, Minute = Text.Type, Sekunde = Text.Type, S_M = Text.Type, S_M_S = Text.Type, #"Stunde #" = number, #"Minute #" = number, #"Sekunde #" = number]
)),
ColumnsToExpand = Table.ColumnNames( GetTableOfTimeComponents[Benutzerdefiniert]{0} ),
#"Erweiterte Benutzerdefiniert" = Table.ExpandTableColumn(GetTableOfTimeComponents, "Benutzerdefiniert", ColumnsToExpand, ColumnsToExpand),
TypenListe =
if Zeiteinheit = "Sekunde" then
{
{"Zeit", type time},
{"Stunde", Text.Type},
{"Minute", Text.Type},
{"Sekunde", Text.Type},
{"S_M", Text.Type},
{"S_M_S", Text.Type},
{"Stunde #", Int64.Type},
{"Minute #", Int64.Type},
{"Sekunde #", Int64.Type}
}
else
if Zeiteinheit = "Minute" then
{
{"Zeit", type time},
{"Stunde", Text.Type},
{"Minute", Text.Type},
{"S_M", Text.Type},
{"Stunde #", Int64.Type},
{"Minute #", Int64.Type}
}
else
{
{"Zeit", type time},
{"Stunde", Text.Type},
{"Stunde #", Int64.Type}
},
#"Geänderter Typ1" = Table.TransformColumnTypes(#"Erweiterte Benutzerdefiniert", TypenListe),
AddCol_Zeitindex = Table.AddIndexColumn(#"Geänderter Typ1", "Zeitindex #", 1, 1, Int64.Type),
//Stunden segmentieren
StundenSegmentieren = Table.AddColumn(AddCol_Zeitindex, "StdSegmentierung", each Number.IntegerDivide([#"Stunde #"], StdSeg), Int64.Type),
#"Gruppierte Zeilen" = Table.Group(StundenSegmentieren, {"StdSegmentierung"}, {{"MinStunde", each List.Min([Stunde]), type nullable number}, {"MaxStunde", each List.Max([Stunde]), type nullable number}}),
StundenBereich = Table.CombineColumns(Table.TransformColumnTypes(#"Gruppierte Zeilen", {{"MinStunde", type text}, {"MaxStunde", type text}}, "de-DE"),{"MinStunde", "MaxStunde"},Combiner.CombineTextByDelimiter(" - ", QuoteStyle.None),"StundenBereich"),
Benutzerdefiniert1 = StundenSegmentieren,
#"Zusammengeführte Abfragen" = Table.NestedJoin(Benutzerdefiniert1, {"StdSegmentierung"}, StundenBereich, {"StdSegmentierung"}, "Benutzerdefiniert1", JoinKind.LeftOuter),
ErgebnisStundenBereich = Table.ExpandTableColumn(#"Zusammengeführte Abfragen", "Benutzerdefiniert1", {"StundenBereich"}, {"StundenBereich"}),
//Minuten sementieren
MinutenSegmentieren = Table.AddColumn(ErgebnisStundenBereich, "MinSegmentierung", each Number.IntegerDivide([#"Minute #"], MinSeg), Int64.Type),
#"Gruppierte Zeilen1" = Table.Group(MinutenSegmentieren, {"MinSegmentierung"}, {{"MinMinuten", each List.Min([Minute]), type nullable number}, {"MaxMinuten", each List.Max([Minute]), type nullable number}}),
MinutenBereich = Table.CombineColumns(Table.TransformColumnTypes(#"Gruppierte Zeilen1", {{"MinMinuten", type text}, {"MaxMinuten", type text}}, "de-DE"),{"MinMinuten", "MaxMinuten"},Combiner.CombineTextByDelimiter(" - ", QuoteStyle.None),"MinutenBereich"),
Benutzerdefiniert2 = MinutenSegmentieren,
#"Zusammengeführte Abfragen1" = Table.NestedJoin(Benutzerdefiniert2, {"MinSegmentierung"}, MinutenBereich, {"MinSegmentierung"}, "Benutzerdefiniert2", JoinKind.LeftOuter),
ErgebnisMinutenBereich = Table.ExpandTableColumn(#"Zusammengeführte Abfragen1", "Benutzerdefiniert2", {"MinutenBereich"}, {"MinutenBereich"}),
//Sekunden segmentieren
SekundenSegmentieren = Table.AddColumn(ErgebnisMinutenBereich, "SekSegmentieren", each Number.IntegerDivide([#"Sekunde #"], SekSeg), Int64.Type),
#"Gruppierte Zeilen2" = Table.Group(SekundenSegmentieren, {"SekSegmentieren"}, {{"MinSekunde", each List.Min([Sekunde]), type nullable text}, {"MaxSekunde", each List.Max([Sekunde]), type nullable text}}),
SekundenBereich = Table.CombineColumns(#"Gruppierte Zeilen2",{"MinSekunde", "MaxSekunde"},Combiner.CombineTextByDelimiter(" - ", QuoteStyle.None),"SekundenBereich"),
Benutzerdefiniert3 = SekundenSegmentieren,
#"Zusammengeführte Abfragen2" = Table.NestedJoin(Benutzerdefiniert3, {"SekSegmentieren"}, SekundenBereich, {"SekSegmentieren"}, "Benutzerdefiniert3", JoinKind.LeftOuter),
ErgebnisSekundenBereich = Table.ExpandTableColumn(#"Zusammengeführte Abfragen2", "Benutzerdefiniert3", {"SekundenBereich"}, {"SekundenBereich"}),
//Weiterer Verlauf
Weiter =
if SekSeg <> null then
ErgebnisSekundenBereich
else
if MinSeg <> null then
ErgebnisMinutenBereich
else
if StdSeg <> null then
ErgebnisStundenBereich
else
AddCol_Zeitindex,
//Alle eventuell bestehenden Segmentierungsspalten löschen, die nur für die Berechnung benötigt wurden
#"Entfernte Spalten" = Table.RemoveColumns(Weiter,{"StdSegmentierung", "MinSegmentierung", "SekSegmentieren"}, MissingField.Ignore)
in
#"Entfernte Spalten"
,
fnType = type function(
Zeiteinheit as (type text meta[Documentation.AllowedValues={"Stunde", "Minute", "Sekunde"}]),
optional StundenSegment as (type number meta[Documentation.AllowedValues={2,3,4,6,8,12}]),
optional MinutenSegment as (type number meta[Documentation.AllowedValues={2,3,4,5,6,10,12,15,20,30}]),
optional SekundenSegment as (type number meta[Documentation.AllowedValues={2,3,4,5,6,10,12,15,20,30}])
) as table meta [
Documentation.Name="fnTimeTable",
Documentation.LongDescription="Diese Funktion erstellt eine Zeittabelle.",
Documentation.Author="Lars Schreiber, ssbi-blog.de"
]
in
Value.ReplaceType(fn, fnType)
view raw fnTimeTable.pq hosted with ❤ by GitHub

Falls Du wissen möchtest, wie Du eine Funktion in Power BI wiederverwendest, findest Du hier eine kurze Anleitung dazu. Als nächstes möchte ich ein paar Worte zu den Parametern dieser Funktion verlieren.

Parameter

Die Funktion benötigt lediglich einen Parameter. Du musst wählen, ob Du die Tabelle mit der Genauigkeit Stunde, Minute oder Sekunde brauchst.

Funktionsparameter: Wähle die gewünschte Zeiteinheit (Stunde, Minute, Sekunde), Power Query, Power BI
Funktionsparameter: Wähle die gewünschte Zeiteinheit (Stunde, Minute, Sekunde) und optionale Zeit-Segmente aus

Je nach Auswahl des Parameters, ergeben sich verschiedene Zeittabellen.

Verschiedene Zeittabellen

Je nach Detaillierungsgrad Deiner Zeittabelle (auf Basis Stunde, Minute oder Sekunde) ergibt sich eine der folgenden drei Tabellen. Schauen wir uns die 3 unterschiedlichen Tabellen näher an.

Tabelle auf Basis der Stunde im Detail

Anzahl Datensätze: 24 – einer pro Stunde

Struktur: Die Spalte Zeit dient als Primärschlüssel für die Beziehung zur Faktentabelle. Die Spalte Stunde liegt in Textform vor und kann damit einfach als Dimension in Visualisierungen oder Slicern genutzt werden.

Tabelle auf Basis der Minute im Detail

Anzahl Datensätze: 1.440 – einer pro Minute.

Struktur: Die Spalte Zeit dient als Primärschlüssel für die Beziehung zur Faktentabelle. Die Spalten Stunde und Minute liegen in Textform vor und können damit einfach als Dimension in Visualisierungen oder Slicern genutzt werden.

Spalte S_M: Diese Spalte kombiniert Stunden und Minuten in Textform miteinander und kann somit ebenfalls einfach als Dimension in Visualisierungen oder Slicern genutzt werden.

Tabelle auf Basis der Sekunde im Detail

Anzahl Datensätze: 86.400 – einer pro Sekunde.

Struktur: Die Spalte Zeit dient als Primärschlüssel für die Beziehung zur Faktentabelle. Die Spalten Stunde, Minute und Sekunde liegen in Textform vor und können damit einfach als Dimension in Visualisierungen oder Slicern genutzt werden.

Spalten S_M und S_M_S: S_M kombiniert Stunden und Minuten in Textform miteinander. S_M_S kombiniert Stunden, Minuten und Sekunden in Textform. Beide Spalten können einfach als Dimension in Visualisierungen oder Slicern genutzt werden.

Zeit-Segmente

Häufig besteht in zeitbezogenen Analysen der Bedarf, Zeiteinheiten zu segmentieren. Man möchte also bspw. nicht jede Minute im Detail sehen, sondern vier Viertelstunden. Hierfür sind meine optionalen Zeit-Segment-Parameter vorhanden, die es Dir ermöglichen, ein Segment je Stunde, Minute und Sekunde zu erstellen.

Im folgenden Video stelle ich Dir die Funktion und dessen Anwendung vor.

Video

Ich hoffe, diese Funktion erleichtert Dir die Arbeit 🙂

Bis zum nächsten Mal und denk dran: Sharing is caring. Wenn Dir der Beitrag gefallen hat, dann teile ihn gerne. Falls Du Anmerkungen hast, schreibe gerne einen Kommentar, oder schicke mir eine Mail an lars@ssbi-blog.de

Viele Grüße aus Hamburg,

Lars

Der Beitrag Meine projekterprobte Zeittabelle für Power BI und Power Pivot erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>