<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged excel</title>
<link>https://coderlegion.com/tag/excel</link>
<description>Powered by Question2Answer</description>
<item>
<title>Distinguishing Excel Subtotal Rows from Detail Rows in SSAS Multidimensional MDX</title>
<link>https://coderlegion.com/23491/distinguishing-excel-subtotal-rows-from-detail-rows-in-ssas-multidimensional-mdx</link>
<description>&lt;p&gt;When connecting Excel PivotTables to an SSAS Multidimensional cube, distinguishing whether a cell belongs to an individual detail row or an aggregated subtotal row is a common challenge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to Achieve It&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To identify row context dynamically in MDX, you leverage the current hierarchy member's position relative to its siblings or descendants.&lt;/p&gt;
&lt;p&gt;Utilize ISLEAF() function to evaluate if the current member in the attribute hierarchy is at the lowest grain.&lt;/p&gt;
&lt;p&gt;Leverage COUNT() with .CHILDREN or .DESCENDANTS to check if the current context represents a set of members rather than a single attribute instance.&lt;/p&gt;
&lt;p&gt;Combine logic with SCOPE statements in the cube's MDX Script to override measure behavior specifically for aggregate levels versus detail levels.&lt;/p&gt;
&lt;p&gt;Problems You Will Encounter&lt;br&gt;
Implementing conditional logic based on aggregation context introduces specific hurdles:&lt;/p&gt;
&lt;p&gt;Subtotal Context Discrepancy: Excel PivotTables do not always query the hierarchy explicitly at the root level; subtotal rows send set-based queries that can evaluate as multiset aggregations rather than standard hierarchy parents.&lt;/p&gt;
&lt;p&gt;Performance Degradation: Applying procedural functions like ISLEAF() or COUNT() inside calculated measures forces cell-by-cell evaluation, bypassing the SSAS formula engine cache and slowing down PivotTable refresh rates.&lt;/p&gt;
&lt;p&gt;Visual Totals Confusion: When filters or slicers are applied in Excel, a subtotal row might evaluate to a single member context, leading MDX script logic to misidentify a subtotal as a detail row.&lt;/p&gt;
&lt;p&gt;How We Solve This Problem&lt;br&gt;
The most robust solution uses the ISLEAF() predicate paired with explicit SCOPE isolation or checking the .CURRENTMEMBER depth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Apply direct leaf-level validation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Code snippet&lt;br&gt;
CASE &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHEN [Product].[Category].CURRENTMEMBER.ISLEAF 
THEN [Measures].[Detail Value]
ELSE [Measures].[Subtotal Value]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;END&lt;br&gt;
&lt;strong&gt;Use SCOPE statements for optimal performance:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Code snippet&lt;br&gt;
/&lt;em&gt; Apply default subtotal logic &lt;/em&gt;/&lt;br&gt;
SCOPE([Measures].[MyMeasure]);&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;THIS = [Measures].[Subtotal Value];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;END SCOPE;&lt;/p&gt;
&lt;p&gt;/&lt;em&gt; Override strictly for leaf-level detail rows &lt;/em&gt;/&lt;br&gt;
SCOPE([Measures].[MyMeasure], [Product].[Category].[Category].MEMBERS);&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;THIS = IF([Product].[Category].CURRENTMEMBER.ISLEAF, [Measures].[Detail Value], [Measures].[Subtotal Value]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;END SCOPE;&lt;/strong&gt;&lt;br&gt;
Filter out multi-select slicer edge cases: Check [Hierarchy].CURRENTMEMBER IS [Hierarchy].[All] or evaluate .LEVEL.ORDINAL to guarantee the calculation knows exact depth within the hierarchy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sumita&lt;br&gt;
Web Developer&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23491/distinguishing-excel-subtotal-rows-from-detail-rows-in-ssas-multidimensional-mdx</guid>
<pubDate>Sun, 26 Jul 2026 08:09:44 +0000</pubDate>
</item>
<item>
<title>php_excel 2.0: The C Extension for Excel That PHP Should Have Had All Along</title>
<link>https://coderlegion.com/16685/phpexcel-2-0-the-c-extension-for-excel-that-php-should-have-had-all-along</link>
<description>&lt;p&gt;PHP processes more Excel files than any language except maybe Python. Payroll exports, inventory imports, financial reports, data migrations. If your business runs on spreadsheets (and it does), your PHP app touches them constantly.&lt;/p&gt;
&lt;p&gt;The standard approach is PhpSpreadsheet: a pure-PHP library that parses XML, builds an in-memory object graph, and promptly devours your server's RAM. It works fine for small files. It falls apart the moment someone uploads a 50,000-row export from SAP. (Don't ask me how I know. )&lt;/p&gt;
&lt;p&gt;php_excel takes a different path. It's a PHP extension that wraps &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.libxl.com/&quot;&gt;LibXL&lt;/a&gt;, a commercial C/C++ library purpose-built for reading and writing Excel files. Unlike most alternatives, LibXL handles both modern xlsx (Office 2007+) and the legacy xls binary format (Excel 97-2003), so you don't need separate codepaths for old and new files.&lt;/p&gt;
&lt;p&gt;Instead of parsing XML in userland PHP, every cell read and write is a single C function call. In my benchmarks it's 7-10x faster than PhpSpreadsheet, and its memory footprint stays flat while PhpSpreadsheet's climbs past a gigabyte.&lt;/p&gt;
&lt;p&gt;Version 2.0 shipped on April 5, 2026. It's the first major release in a long while, and it brings the extension fully into modern PHP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Changed in 2.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The last official release (1.0.2) dates back to 2016. There was an unreleased 1.0.3 with PHP 7 support contributed by community members a few years later, but it never shipped. PHP has changed a lot since then. 2.0 is a ground-up modernization:&lt;/p&gt;
&lt;p&gt;PHP 8.3 is the minimum version. Full support for 8.4, 8.5, and the development master branch. The extension builds and tests clean against all four, with zero warnings. On the LibXL side, the minimum is 4.6.0 (released over a year ago), with support up to the latest 5.1.0. I gate newer LibXL features at compile time: you get everything your installed version supports, and the extension still builds clean against 4.6.0.&lt;/p&gt;
&lt;p&gt;2.0 adds six new classes to the existing six:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ExcelRichString&lt;/strong&gt;: mixed-font text in a single cell (bold the header, italicize the footnote)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ExcelFormControl&lt;/strong&gt;: checkboxes, dropdowns, spinners, buttons, and other form widgets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ExcelConditionalFormat&lt;/strong&gt; / &lt;strong&gt;ExcelConditionalFormatting&lt;/strong&gt;: conditional formatting rules and their application to cell ranges&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ExcelCoreProperties&lt;/strong&gt;: workbook metadata (title, author, creation dates, categories)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ExcelTable&lt;/strong&gt;: structured table support for xlsx&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I added methods across every existing class. ExcelBook now handles rich strings, conditional formats, VBA removal, DPI awareness, and picture-as-link support. ExcelSheet got pixel-based column/row sizing, tab colors, active cell management, selection ranges, form controls, data validation, and structured tables.&lt;/p&gt;
&lt;p&gt;Every parameter and return type now has proper arginfo. That's 399 typed parameters and 277 typed return values, which means IDE autocompletion and static analysis tools actually work with the extension.&lt;/p&gt;
&lt;p&gt;I also cleaned up the internals. Constructors now throw exceptions on error instead of silently returning false. I fixed several use-after-free bugs, null pointer dereferences, and memory leaks, the kind of issues that only surface under heavy load or with AddressSanitizer enabled. Serialization is disabled on all classes (serializing a file handle was never going to end well). The full list is in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/php_excel/blob/master/ChangeLog&quot;&gt;ChangeLog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why a C Extension?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PHP's process-per-request model means every request starts from scratch. When PhpSpreadsheet opens a 100,000-row file, it parses the underlying XML with SimpleXML (DOM-based, so the entire XML tree lives in memory), then builds a Cell object for every cell with coordinate indexes, style references, and type metadata. In my benchmarks, PhpSpreadsheet 5.5 used about 1,066 MB to load 2 million cells, roughly 0.5 KB per cell for the object graph alone. That's already over a gigabyte for a single 100,000-row sheet. Add formatting, and it climbs further.&lt;/p&gt;
&lt;p&gt;LibXL does the same work in optimized C/C++. The XML parsing, ZIP decompression, and cell storage all happen in native code. The extension itself is a thin translation layer: it takes PHP zvals, converts them to C types, calls the LibXL function, and converts the result back. The overhead per cell is a few hundred nanoseconds.&lt;/p&gt;
&lt;p&gt;LibXL still uses real memory on the C heap for its internal workbook structures, so this isn't a free lunch. But it uses that memory more efficiently than PhpSpreadsheet's PHP object graph, and it's close to an order of magnitude faster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Benchmarks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I ran these on PHP 8.4.19 (release build, NTS) against PhpSpreadsheet 5.5.0. Each test writes or reads a mix of integers, floats, and strings across 20 columns. Same data, same machine, measured with &lt;code&gt;hrtime()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's the php_excel write test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$book = new ExcelBook(null, null, true); // xlsx mode
$sheet = $book-&amp;gt;addSheet(&amp;#x27;Bench&amp;#x27;);

for ($r = 1; $r &amp;lt;= $rows; $r++) {
    for ($c = 0; $c &amp;lt; $cols; $c++) {
        if ($c % 3 === 0) {
            $sheet-&amp;gt;write($r, $c, $r * $cols + $c);        // integer
        } elseif ($c % 3 === 1) {
            $sheet-&amp;gt;write($r, $c, &amp;quot;Row{$r}_Col{$c}_Text&amp;quot;);  // string
        } else {
            $sheet-&amp;gt;write($r, $c, $r * 1.5 + $c * 0.3);    // float
        }
    }
}
$book-&amp;gt;save($outFile);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the PhpSpreadsheet equivalent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet-&amp;gt;getActiveSheet();

for ($r = 1; $r &amp;lt;= $rows; $r++) {
    for ($c = 1; $c &amp;lt;= $cols; $c++) {
        if (($c - 1) % 3 === 0) {
            $sheet-&amp;gt;setCellValue([$c, $r], $r * $cols + $c);
        } elseif (($c - 1) % 3 === 1) {
            $sheet-&amp;gt;setCellValue([$c, $r], &amp;quot;Row{$r}_Col{$c}_Text&amp;quot;);
        } else {
            $sheet-&amp;gt;setCellValue([$c, $r], $r * 1.5 + $c * 0.3);
        }
    }
}
$writer = new Xlsx($spreadsheet);
$writer-&amp;gt;save($outFile);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Write results&lt;/strong&gt; (time / total process memory via VmPeak):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Rows &lt;/th&gt;&lt;th&gt;Cells &lt;/th&gt;&lt;th&gt;php_excel &lt;/th&gt;&lt;th&gt;PhpSpreadsheet &lt;/th&gt;&lt;th&gt;Speed&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1,000 &lt;/td&gt;&lt;td&gt;20K &lt;/td&gt;&lt;td&gt;0.05s / 85 MB &lt;/td&gt;&lt;td&gt;0.45s / 162 MB &lt;/td&gt;&lt;td&gt;&lt;strong&gt;10x&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10,000 &lt;/td&gt;&lt;td&gt;200K &lt;/td&gt;&lt;td&gt;0.55s / 153 MB &lt;/td&gt;&lt;td&gt;4.59s / 282 MB &lt;/td&gt;&lt;td&gt;&lt;strong&gt;9x&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;50,000 &lt;/td&gt;&lt;td&gt;1M &lt;/td&gt;&lt;td&gt;2.72s / 508 MB &lt;/td&gt;&lt;td&gt;24.7s / 790 MB &lt;/td&gt;&lt;td&gt;&lt;strong&gt;9x&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;100,000 &lt;/td&gt;&lt;td&gt;2M &lt;/td&gt;&lt;td&gt;5.37s / 908 MB &lt;/td&gt;&lt;td&gt;51.1s / 1,415 MB &lt;/td&gt;&lt;td&gt;&lt;strong&gt;10x&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All memory figures are total process RSS (VmPeak from &lt;code&gt;/proc/self/status&lt;/code&gt;), including the C heap. LibXL does use real memory for its internal structures, so php_excel isn't &quot;free&quot; on that front. But even counting everything, it uses 40-65% of what PhpSpreadsheet needs and finishes 9-10x faster.&lt;/p&gt;
&lt;p&gt;One practical detail: PHP's &lt;code&gt;memory_get_peak_usage()&lt;/code&gt; reports 2 MB for php_excel throughout, versus 1,254 MB for PhpSpreadsheet at 100K rows. LibXL allocates on the C heap, invisible to PHP's memory manager and &lt;code&gt;memory_limit&lt;/code&gt;. If your PHP-FPM pool has a 128 MB memory_limit, PhpSpreadsheet will OOM on a 10K-row file. php_excel won't.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read results&lt;/strong&gt; (time / total process memory via VmPeak):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Rows &lt;/th&gt;&lt;th&gt;Cells &lt;/th&gt;&lt;th&gt;php_excel &lt;/th&gt;&lt;th&gt;PhpSpreadsheet &lt;/th&gt;&lt;th&gt;OpenSpout&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1,000 &lt;/td&gt;&lt;td&gt;20K &lt;/td&gt;&lt;td&gt;0.05s / 83 MB &lt;/td&gt;&lt;td&gt;0.39s / 175 MB &lt;/td&gt;&lt;td&gt;0.16s / 126 MB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10,000 &lt;/td&gt;&lt;td&gt;200K &lt;/td&gt;&lt;td&gt;0.47s / 144 MB &lt;/td&gt;&lt;td&gt;3.74s / 578 MB &lt;/td&gt;&lt;td&gt;1.48s / 130 MB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;50,000 &lt;/td&gt;&lt;td&gt;1M &lt;/td&gt;&lt;td&gt;2.60s / 422 MB &lt;/td&gt;&lt;td&gt;20.1s / 2,317 MB &lt;/td&gt;&lt;td&gt;8.00s / 130 MB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;100,000 &lt;/td&gt;&lt;td&gt;2M &lt;/td&gt;&lt;td&gt;5.19s / 767 MB &lt;/td&gt;&lt;td&gt;40.8s / 4,501 MB &lt;/td&gt;&lt;td&gt;16.6s / 130 MB&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Three different profiles. php_excel is fastest but uses memory proportional to the file (LibXL loads the whole workbook). PhpSpreadsheet is slowest and its memory explodes, 4.5 GB for 100K rows. OpenSpout streams row by row, so memory stays flat at 130 MB regardless of size, but it's 3x slower than php_excel.&lt;/p&gt;
&lt;p&gt;To be fair to PhpSpreadsheet: it's the most feature-complete pure-PHP Excel library. If you don't need a C extension and your files stay under a few thousand rows, it works fine. Past that, it doesn't.&lt;/p&gt;
&lt;p&gt;OpenSpout fills a different niche. It can't do random cell access, conditional formatting, formulas, rich text, form controls, or xls format. If your workload is &quot;read CSV-like data from xlsx,&quot; it's a good free choice. If you need actual Excel features, it won't help.&lt;/p&gt;
&lt;p&gt;php_excel gives you C library speed with the full Excel feature set. The tradeoff: LibXL requires a commercial license, and installing a C extension takes more effort than &lt;code&gt;composer require&lt;/code&gt;. Whether that tradeoff makes sense depends on your workload. If you're generating a 200-row report once a day, PhpSpreadsheet is fine. If you're processing bulk imports, financial data, or anything where users upload files of unpredictable size, the C extension pays for itself quickly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code Examples&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Creating a workbook and writing data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$book = new ExcelBook();
$sheet = $book-&amp;gt;addSheet(&amp;#x27;Sales Q1&amp;#x27;);

// Headers
$boldFont = new ExcelFont($book);
$boldFont-&amp;gt;bold(true);
$headerFormat = new ExcelFormat($book);
$headerFormat-&amp;gt;font($boldFont);

$headers = [&amp;#x27;ID&amp;#x27;, &amp;#x27;Date&amp;#x27;, &amp;#x27;Customer&amp;#x27;, &amp;#x27;Amount&amp;#x27;, &amp;#x27;Status&amp;#x27;];
foreach ($headers as $col =&amp;gt; $header) {
    $sheet-&amp;gt;write(1, $col, $header, $headerFormat);
}

// Data rows
$data = [
    [1001, &amp;#x27;2026-03-15&amp;#x27;, &amp;#x27;Acme Corp&amp;#x27;, 15750.00, &amp;#x27;Paid&amp;#x27;],
    [1002, &amp;#x27;2026-03-16&amp;#x27;, &amp;#x27;Globex Inc&amp;#x27;, 8200.50, &amp;#x27;Pending&amp;#x27;],
    [1003, &amp;#x27;2026-03-17&amp;#x27;, &amp;#x27;Initech&amp;#x27;, 42000.00, &amp;#x27;Paid&amp;#x27;],
];

$dateFormat = new ExcelFormat($book);
$dateFormat-&amp;gt;numberFormat(ExcelFormat::NUMFORMAT_DATE);

$row = 2;
foreach ($data as $record) {
    $sheet-&amp;gt;write($row, 0, $record[0]);
    $sheet-&amp;gt;write($row, 1, strtotime($record[1]), $dateFormat, ExcelFormat::AS_DATE);
    $sheet-&amp;gt;write($row, 2, $record[2]);
    $sheet-&amp;gt;write($row, 3, $record[3]);
    $sheet-&amp;gt;write($row, 4, $record[4]);
    $row++;
}

// Summary formula
$sheet-&amp;gt;write($row, 3, &amp;#x27;=SUM(D2:D4)&amp;#x27;);

$book-&amp;gt;save(&amp;#x27;sales-q1.xlsx&amp;#x27;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading an uploaded file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$book = new ExcelBook();
$book-&amp;gt;loadFile($_FILES[&amp;#x27;report&amp;#x27;][&amp;#x27;tmp_name&amp;#x27;]);

$sheet = $book-&amp;gt;getSheet(0);
$lastRow = $sheet-&amp;gt;lastFilledRow();
$lastCol = $sheet-&amp;gt;lastFilledCol();

for ($row = $sheet-&amp;gt;firstFilledRow(); $row &amp;lt;= $lastRow; $row++) {
    $rowData = $sheet-&amp;gt;readRow($row, 0, $lastCol);
    // process $rowData
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rich text in a single cell:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$book = new ExcelBook();
$sheet = $book-&amp;gt;addSheet(&amp;#x27;Notes&amp;#x27;);

$richString = $book-&amp;gt;addRichString();

$boldFont = new ExcelFont($book);
$boldFont-&amp;gt;bold(true);

$richString-&amp;gt;addText(&amp;#x27;Important: &amp;#x27;, $boldFont);
$richString-&amp;gt;addText(&amp;#x27;Review before end of quarter.&amp;#x27;);

$sheet-&amp;gt;writeRichStr(1, 0, $richString);
$book-&amp;gt;save(&amp;#x27;notes.xlsx&amp;#x27;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Working with conditional formatting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$book = new ExcelBook();
$sheet = $book-&amp;gt;addSheet(&amp;#x27;Metrics&amp;#x27;);

// Write some data
for ($row = 1; $row &amp;lt;= 20; $row++) {
    $sheet-&amp;gt;write($row, 0, rand(0, 100));
}

// Highlight cells above 75 in green
$cf = $book-&amp;gt;addConditionalFormat();
$cf-&amp;gt;font()-&amp;gt;bold(true);
$cf-&amp;gt;font()-&amp;gt;color(ExcelFont::COLOR_GREEN);

$formatting = $sheet-&amp;gt;addConditionalFormatting();
$formatting-&amp;gt;addRange(1, 0, 20, 0);
$formatting-&amp;gt;addRule(
    ExcelConditionalFormat::CELLIS,
    $cf,
    ExcelConditionalFormat::OPERATOR_GREATERTHAN,
    &amp;#x27;75&amp;#x27;
);

$book-&amp;gt;save(&amp;#x27;metrics.xlsx&amp;#x27;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Linux / macOS&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, get LibXL 4.6.0 or newer from &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.libxl.com/&quot;&gt;libxl.com&lt;/a&gt;. It's a commercial library; there's a trial version that works without a license key (limited to ~300 cells and row 0 is inaccessible).&lt;/p&gt;
&lt;p&gt;The easiest path is &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/php/pie&quot;&gt;PIE&lt;/a&gt; (PHP Installer for Extensions), the official PECL replacement. I added PIE support as part of 2.0:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pie install iliaal/php-excel \
  --with-libxl-incdir=/opt/libxl/include_c \
  --with-libxl-libdir=/opt/libxl/lib64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or build from source:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/iliaal/php_excel.git
cd php_excel
phpize
./configure --with-excel \
  --with-libxl-incdir=/opt/libxl/include_c \
  --with-libxl-libdir=/opt/libxl/lib64
make
sudo make install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add to your &lt;code&gt;php.ini&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extension=excel.so&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure the LibXL shared library is in your linker path. Either install it to a standard location or set &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;quot;/opt/libxl/lib64&amp;quot; | sudo tee /etc/ld.so.conf.d/libxl.conf
sudo ldconfig&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Windows&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Pre-built DLLs for PHP 8.3 and 8.4 (both x64 and x86, TS and NTS) are attached to every &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/php_excel/releases&quot;&gt;GitHub release&lt;/a&gt;. Download the DLL matching your PHP version and architecture, drop it into your &lt;code&gt;ext&lt;/code&gt; directory, and add to &lt;code&gt;php.ini&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extension=excel&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You'll also need &lt;code&gt;libxl.dll&lt;/code&gt; from the LibXL Windows distribution placed somewhere in your system PATH, or in the same directory as &lt;code&gt;php.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;License Key Configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you have a LibXL license, store the credentials in &lt;code&gt;php.ini&lt;/code&gt; rather than your source code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[excel]
excel.license_name=&amp;quot;Your Name&amp;quot;
excel.license_key=&amp;quot;your-license-key-here&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The extension reads these automatically. Pass &lt;code&gt;null&lt;/code&gt; for the license parameters in the ExcelBook constructor and they'll be picked up from the ini settings.&lt;/p&gt;
&lt;p&gt;The extension is open source under the PHP-3.01 license. LibXL itself requires a &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.libxl.com/&quot;&gt;commercial license&lt;/a&gt; for production use.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/php_excel&quot;&gt;Source on GitHub&lt;/a&gt;. Issues, PRs, and stars welcome.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/16685/phpexcel-2-0-the-c-extension-for-excel-that-php-should-have-had-all-along</guid>
<pubDate>Mon, 04 May 2026 19:48:44 +0000</pubDate>
</item>
<item>
<title>Excel Exporter</title>
<link>https://coderlegion.com/9446/excel-exporter</link>
<description>&lt;p&gt;Excel / VBA folks – quick share&lt;/p&gt;
&lt;p&gt;I’ve released a small Windows tool I built out of real-world frustration:&lt;/p&gt;
&lt;p&gt;Excel Exporter.&lt;/p&gt;
&lt;p&gt;It does one thing well:&lt;/p&gt;
&lt;p&gt; exports Excel code objects (modules, classes, forms) from Excel files into clean files on disk.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://lnkd.in/dkyAfqsj&quot;&gt;https://lnkd.in/dkyAfqsj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It comes as Free and Pro Edition&lt;/p&gt;
&lt;p&gt;About the Free Edition&lt;/p&gt;
&lt;p&gt;The Free Edition is fully functional for single Excel files:&lt;/p&gt;
&lt;p&gt;Works with all common Excel formats (.xls, .xlsx, .xlsm, .xlsb, .xla, .xlam, etc.)&lt;/p&gt;
&lt;p&gt;Exports clean .bas, .cls, .frm files&lt;/p&gt;
&lt;p&gt;Organizes everything into a folder named after the workbook&lt;/p&gt;
&lt;p&gt;Optional ZIP export&lt;/p&gt;
&lt;p&gt;If you work with one Excel file at a time, the free version is honestly enough.&lt;/p&gt;
&lt;p&gt;What the PRO adds (and why it exists)&lt;/p&gt;
&lt;p&gt;The PRO edition doesn’t unlock “power” — it unlocks convenience:&lt;/p&gt;
&lt;p&gt;Batch export from folders (lots of Excel files at once)&lt;/p&gt;
&lt;p&gt;Command-line (CLI) support for automation&lt;/p&gt;
&lt;p&gt;This is useful if you:&lt;/p&gt;
&lt;p&gt;Maintain many Excel/VBA files&lt;/p&gt;
&lt;p&gt;Need to audit legacy systems&lt;/p&gt;
&lt;p&gt;Want to integrate exports into scripts or CI jobs&lt;/p&gt;
&lt;p&gt;Example CLI usage (PRO):&lt;/p&gt;
&lt;p&gt;ExcelExporter.exe -file &quot;c:\Projects\MyExcel.xlsm&quot; -modules -classes -forms&lt;/p&gt;
&lt;p&gt;If you’re interested in the PRO version: &lt;/p&gt;
&lt;p&gt;Email me at &lt;em&gt;Emails are not allowed&lt;/em&gt; (P.S. Pro edition $5)&lt;/p&gt;
&lt;p&gt;Payments via PayPal or Wise.&lt;/p&gt;
&lt;p&gt;I’ll send you the PRO build and (optionally) add you to the private GitHub repo.&lt;/p&gt;
&lt;p&gt;If not — the Free Edition is open-source and works perfectly for single files.&lt;/p&gt;
&lt;p&gt;Sharing in case it helps someone dealing with VBA-heavy Excel systems (we all know how painful those can be).&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/9446/excel-exporter</guid>
<pubDate>Fri, 09 Jan 2026 12:25:29 +0000</pubDate>
</item>
<item>
<title>[Review] 20250620: The Plan to Supersede Excel</title>
<link>https://coderlegion.com/3376/review-20250620-the-plan-to-supersede-excel</link>
<description>&lt;p&gt;Soon enough, Divooka is almost here. Let's go back to the problem that got us started: practical data analytics at scale.&lt;/p&gt;
&lt;p&gt;We're not trying to completely replace Excel. Excel serves its purposes extremely well, and we envision a world where tools are more specialized depending on the needs. On the other hand, many of the problems Divooka aims to solve - particularly in data analytics - stem from &lt;em&gt;overuse&lt;/em&gt; or &lt;em&gt;misuse&lt;/em&gt; of Excel in situations it was never designed for. That's why Excel naturally becomes a benchmark for evaluating how well Divooka addresses these challenges - and in turn, how effectively Divooka can substitute for Excel in those contexts.&lt;/p&gt;
&lt;p&gt;In general, the future we're building toward is one where people only use Excel occasionally - for working with legacy systems or exchanging files with external clients. For all other practical, internal, and repeatable analytical tasks, organizations and individuals shouldn't have to open Excel at all. That's the vision for Divooka in the data analytics space.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; If you're wondering why we compare ourselves to Excel when talking about &quot;data analytics&quot; rather than Python - it's because we're focusing on where actual work gets done by everyday professionals in finance, retail, consulting, etc. - outside of data scientists and machine learning engineers, who typically work within well-defined infrastructures or theoretical environments.&lt;/p&gt;
&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;Excel offers the following main functionalities and use cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using worksheets/workbooks as informal databases – enabling data entry, filtering, etc.&lt;/li&gt;
&lt;li&gt;Applying formulas for analytics – calculating sums, performing aggregates, lookups.&lt;/li&gt;
&lt;li&gt;Plotting and reporting – generating charts and formatted reports.&lt;/li&gt;
&lt;li&gt;Automating results and, to some extent, content – via templates for repeated use.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;a-note-on-learning&quot;&gt;A Note on Learning&lt;/h3&gt;
&lt;p&gt;Some claim Excel is easier to learn than Python or Divooka. In our experience, that perception usually comes from people who've been using Excel for 10+ years. That certainly wasn't my experience when I first tried to learn it - by then, I was already an experienced programmer.&lt;/p&gt;
&lt;p&gt;Excel has a lot of quirks. Fortunately, it also has a wealth of online resources - forums, tutorials, and StackOverflow answers - that help users troubleshoot specific needs quickly. But that doesn't necessarily make it easier to learn.&lt;/p&gt;
&lt;p&gt;Meanwhile, its automation and extension system (VBA, VSTO) and DOM model are far from elegant. They can be powerful - but they're also idiosyncratic, outdated, and hard to scale or maintain.&lt;/p&gt;
&lt;h3 id=&quot;identifying-veteran-use&quot;&gt;Identifying Veteran Use&lt;/h3&gt;
&lt;p&gt;For veteran users - those who've worked in finance, consulting, banking, or retail for over a decade - it's crucial to identify what matters most to them so we don't waste time trying to rebuild everything from scratch.&lt;/p&gt;
&lt;p&gt;For these professionals, usually in management roles, key priorities tend to be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Simple data entry&lt;/li&gt;
&lt;li&gt;Basic formulas (especially VLOOKUP and IF logic) and pivot tables&lt;/li&gt;
&lt;li&gt;Minimal plotting&lt;/li&gt;
&lt;li&gt;Extensive styling, including conditional formatting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Veterans rarely write VBA or build complex automated spreadsheets themselves - that's what interns and junior staff are usually tasked with.&lt;/p&gt;
&lt;h3 id=&quot;the-solution-plan&quot;&gt;The Solution Plan&lt;/h3&gt;
&lt;p&gt;Divooka already outperforms Excel in areas like analytics and automation (points 3 and 4), but matching Excel's GUI experience for basic data entry and formulas remains a challenge.&lt;/p&gt;
&lt;h4 id=&quot;the-challenges&quot;&gt;The Challenges&lt;/h4&gt;
&lt;p&gt;The problem can be broken down into two fronts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We must provide a familiar interface and usage pattern - even though Divooka is not Excel - to reduce resistance from long-time Excel users.&lt;/li&gt;
&lt;li&gt;Divooka is a visual programming language with its own design principles. While we want to be &lt;em&gt;similar to Excel&lt;/em&gt; where needed, we must stay true to what makes Divooka powerful and unique.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;the-approaches&quot;&gt;The Approaches&lt;/h4&gt;
&lt;p&gt;To address the GUI/database usage pattern, we're exploring a few possible approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a custom visual node that replicates the structure of a standard Excel worksheet - though it might look more like a clean, modern take similar to Apple Numbers.&lt;/li&gt;
&lt;li&gt;Encourage users to adopt API-driven or externalized databases and foster a mindset of separating &lt;em&gt;data&lt;/em&gt;, &lt;em&gt;computation&lt;/em&gt;, and &lt;em&gt;presentation&lt;/em&gt;. While we offer SQL and database API integration out of the box, we also recognize that many users resist this - even if they're already managing convoluted Excel formulas.&lt;/li&gt;
&lt;li&gt;On that note, there are two directions we're exploring:&lt;ul&gt;
&lt;li&gt;Provide a visual interface (like MySQL Workbench) for common database operations.&lt;/li&gt;
&lt;li&gt;Offer a high-level, node-based API that avoids manual SQL writing, while gently encouraging users to become more familiar with what's happening under the hood.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;a-combined-use-case&quot;&gt;A Combined Use Case&lt;/h4&gt;
&lt;p&gt;The most common (and most problematic) Excel use case is when people combine:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Data entry,&lt;/li&gt;
&lt;li&gt;Basic automated calculations,&lt;/li&gt;
&lt;li&gt;Fancy styling,&lt;/li&gt;
&lt;li&gt;Plots and form updates for reporting purposes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is where Excel shines - and also where it often gets &lt;em&gt;abused&lt;/em&gt;. It enables incredibly compact and self-contained workflows: enter numbers, add formulas, apply some styling - and voilà, you have a polished report.&lt;/p&gt;
&lt;p&gt;But this convenience comes at a cost: poor scalability, maintainability issues, and a lack of clear separation of concerns. A single cell can simultaneously serve as a data source, a computed result, and a styled report element. This makes downstream changes, automation, and collaboration extremely hard.&lt;/p&gt;
&lt;p&gt;The traditional software engineering solution is seen in the web: HTML (structure), CSS (style), and JavaScript (logic). By clearly separating concerns, we maintain flexibility and clarity. So what if creating an HTML/CSS/JS-based dashboard was &lt;em&gt;as easy&lt;/em&gt; as building an Excel sheet? That's one possible angle - and something Divooka could eventually support through node APIs or higher-level content editors.&lt;/p&gt;
&lt;p&gt;But that's not the most elegant path forward.&lt;/p&gt;
&lt;h4 id=&quot;the-real-solution&quot;&gt;The Real Solution&lt;/h4&gt;
&lt;p&gt;The better question to ask is: what is the actual &lt;em&gt;end goal&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;People want to build interactive dashboards or reports that auto-update, look professional, and live within a single workspace where they can easily edit data, adjust formulas, and customize visuals - all while staying clean and maintainable.&lt;/p&gt;
&lt;p&gt;Wait a second - doesn't that sound like &lt;strong&gt;&lt;em&gt;App Mode&lt;/em&gt;&lt;/strong&gt; in Neo?&lt;/p&gt;
&lt;p&gt;(Screenshot coming soon when the time is right.)&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Divooka was never about &quot;replacing Excel&quot; outright. That was never the goal - and still isn't. What we set out to solve was broader and deeper: making practical, scalable data analytics accessible to professionals who are otherwise stuck with brittle, overextended workflows. Excel simply happens to be the dominant tool in that space, so it naturally became both our benchmark and our foil.&lt;/p&gt;
&lt;p&gt;In a sense, replacing Python is an easier problem - just design a better language, with better libraries and ecosystem. Julia is doing that, so are many others. When we started tackling &quot;The Excel Problem,&quot; it felt vague and enormous. We only had instincts: &quot;There must be a better way,&quot; and &quot;Visual programming, like Divooka, seems right.&quot; Back then, we didn't yet see the full shape of the solution.&lt;/p&gt;
&lt;p&gt;But as Divooka matures, as our libraries evolve, and as our design principles solidify, the picture becomes clearer.&lt;/p&gt;
&lt;p&gt;It's becoming evident that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Data entry can be streamlined through a combination of high-level APIs and dedicated GUIs.&lt;/li&gt;
&lt;li&gt;Dedicated graphical editors are not just useful - they're &lt;em&gt;the future&lt;/em&gt;. We'll share more on this next year.&lt;/li&gt;
&lt;li&gt;Divooka's graph-based mindset is not only powerful but &lt;em&gt;practical&lt;/em&gt;. Neo will serve as the reference implementation and the litmus test for what a modern visual programming platform can achieve.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, there are still many UX and ergonomics problems to solve - and we must proceed with care.&lt;/p&gt;
&lt;p&gt;But we're getting close.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/Divooka/Techniques/AppMode&quot;&gt;App Mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Divooka</category>
<guid isPermaLink="true">https://coderlegion.com/3376/review-20250620-the-plan-to-supersede-excel</guid>
<pubDate>Fri, 20 Jun 2025 13:50:46 +0000</pubDate>
</item>
<item>
<title>How to Create a Date Table in Power Query</title>
<link>https://coderlegion.com/1884/how-to-create-a-date-table-in-power-query</link>
<description>&lt;p&gt;A Date table is needed for analysis in Power BI because it helps organize and analyze data by date. As the name implies, it enables you to create a calendar (date information) that works for the analysis you want to carry out. i.e weekday, month &amp;amp; year analysis.&lt;/p&gt;
&lt;h3 id=&quot;why-is-date-table-important-in-power-bi-&quot;&gt;Why is Date Table important in Power BI?&lt;/h3&gt;
&lt;p&gt;It can be used for a variety of purposes, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filtering data: It can filter data by specific date attributes, such as month, quarter, year, or weekday.&lt;/li&gt;
&lt;li&gt;Creating visuals: It helps in creating visuals with dynamic periods, such as the current quarter or month.&lt;/li&gt;
&lt;li&gt;Comparing data: It helps in comparing data over time, such as from&lt;br&gt;
one year to the next or from one month to the next.&lt;/li&gt;
&lt;li&gt;Using DAX time intelligence functions: You can use DAX time&lt;br&gt;
intelligence functions that wouldn’t normally work without a date&lt;br&gt;
table.&lt;/li&gt;
&lt;li&gt;Optimizing data model: When working with large data sets, a separate&lt;br&gt;
date table can help you establish associations between your data&lt;br&gt;
tables and the date table. This can help you boost productivity,&lt;br&gt;
cross-functional reporting, and optimize your data model.&lt;/li&gt;
&lt;li&gt;Standardizing date formatting: It can help create standardized date&lt;br&gt;
formatting. Improving data modeling: It can improve data modeling.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check out BI Samurai for more explanation on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=vTz2Mxt7npY&quot;&gt;why you need a date table&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A date table can be created in Power Query or DAX. In this article, you will be creating your date table in Power Query.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-date-table-in-power-query&quot;&gt;Creating a Date Table in Power Query&lt;/h3&gt;
&lt;p&gt;Open Power Query, &lt;strong&gt;Home&lt;/strong&gt;&amp;gt;&amp;gt;&lt;strong&gt;&lt;em&gt;Transform Data&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=3221893590656766253&quot; alt=&quot;create a blank query&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click on the New Source dropdown and Create a blank query.&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1039528538741641440&quot; alt=&quot;&quot;&gt;&lt;br&gt;
In the formula bar, write an M code to compute the date list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;= List.Dates(#date(2025,1,1), 365, #duration(1,0,0,0))
List.Dates(start as date, count as number, step as duration)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;List.Dates: the list.date function take 3 arguments (parameters)&lt;/li&gt;
&lt;li&gt;start as date: the date you want to start from&lt;/li&gt;
&lt;li&gt;count as number: the number you want it to count from the start date&lt;/li&gt;
&lt;li&gt;step as duration: the number of days, hours, minutes or seconds you&lt;br&gt;
want to count from the start date.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the code above, the start date is the 1st of January 2025, then count 365 of the duration arguments. The #duration arguments have (1,0,0,0) which translates to 1 day, 0 hour, 0 minute, and 0 second.&lt;/p&gt;
&lt;p&gt;In this case, the date will start from &lt;strong&gt;&lt;em&gt;2025–01–01&lt;/em&gt;&lt;/strong&gt; and &lt;em&gt;count 365 days&lt;/em&gt; from the start date, and that’s what will return in your query.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12635458205200536425&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once a list column has been created, right-click on the column and convert the list to a table (that’s what Power Query allows transformation on).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=9653536742666671699&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Leave delimiter as &lt;strong&gt;None&lt;/strong&gt;. Then click &lt;strong&gt;OK&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;: if you have data that contains a list of items i.e. [dogs, cats, birds] etc. The delimiter in this scenario is the comma separating those items, and if there is a row that doesn’t have a list value, how it will handle it is the second option in the prompt box.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=8302681077345617792&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now it’s in table format. (tabular structure)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=16445648547649391784&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Change the data type and rename the column, go to &lt;strong&gt;Add Column&lt;/strong&gt;&amp;gt;&amp;gt;&lt;strong&gt;Date&lt;/strong&gt; and start selecting other date parameters to form the calendar table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt;: Make sure the Date column is selected before adding a new column.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1257601310870484156&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10904959118653488391&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can get the scripts to replicate yours&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let
Source = List.Dates(#date(2025,1,1), 365, #duration(1,0,0,0)),
#&quot;Converted to Table&quot; = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#&quot;Changed Type&quot; = Table.TransformColumnTypes(#&quot;Converted to Table&quot;,{{&quot;Column1&quot;, type date}}),
#&quot;Renamed Columns&quot; = Table.RenameColumns(#&quot;Changed Type&quot;,{{&quot;Column1&quot;, &quot;Date&quot;}}),
#&quot;Inserted Year&quot; = Table.AddColumn(#&quot;Renamed Columns&quot;, &quot;Year&quot;, each Date.Year([Date]), Int64.Type),
#&quot;Inserted Start of Year&quot; = Table.AddColumn(#&quot;Inserted Year&quot;, &quot;Start of Year&quot;, each Date.StartOfYear([Date]), type date),
#&quot;Inserted End of Year&quot; = Table.AddColumn(#&quot;Inserted Start of Year&quot;, &quot;End of Year&quot;, each Date.EndOfYear([Start of Year]), type date),
#&quot;Inserted Month&quot; = Table.AddColumn(#&quot;Inserted End of Year&quot;, &quot;Month&quot;, each Date.Month([Date]), Int64.Type),
#&quot;Inserted Month Name&quot; = Table.AddColumn(#&quot;Inserted Month&quot;, &quot;Month Name&quot;, each Date.MonthName([Date]), type text),
#&quot;Inserted Days in Month&quot; = Table.AddColumn(#&quot;Inserted Month Name&quot;, &quot;Days in Month&quot;, each Date.DaysInMonth([Date]), Int64.Type),
#&quot;Inserted Start of Month&quot; = Table.AddColumn(#&quot;Inserted Days in Month&quot;, &quot;Start of Month&quot;, each Date.StartOfMonth([Date]), type date),
#&quot;Inserted End of Month&quot; = Table.AddColumn(#&quot;Inserted Start of Month&quot;, &quot;End of Month&quot;, each Date.EndOfMonth([Date]), type date),
#&quot;Inserted Quarter&quot; = Table.AddColumn(#&quot;Inserted End of Month&quot;, &quot;Quarter&quot;, each Date.QuarterOfYear([Date]), Int64.Type),
#&quot;Inserted Start of Quarter&quot; = Table.AddColumn(#&quot;Inserted Quarter&quot;, &quot;Start of Quarter&quot;, each Date.StartOfQuarter([Date]), type date),
#&quot;Inserted End of Quarter&quot; = Table.AddColumn(#&quot;Inserted Start of Quarter&quot;, &quot;End of Quarter&quot;, each Date.EndOfQuarter([Date]), type date),
AddColumns = Table.AddColumn(#&quot;Inserted End of Quarter&quot;, &quot;Month Name Short&quot;, each Date.ToText([Date], &quot;MMM&quot;), type text),
AddMonthAndDay = Table.AddColumn(AddColumns, &quot;Month &amp;amp; Day&quot;, each Date.ToText([Date], &quot;MMM&quot;) &amp;amp; &quot; &quot; &amp;amp; Text.From(Date.Day([Date])), type text),
AddMonthAndYear = Table.AddColumn(AddMonthAndDay, &quot;Month &amp;amp; Year&quot;, each Date.ToText([Date], &quot;MMM&quot;) &amp;amp; &quot;-&quot; &amp;amp; Date.ToText([Date], &quot;yyyy&quot;), type text),
AddYearMonthNum = Table.AddColumn(AddMonthAndYear, &quot;Year Month Num&quot;, each Number.FromText(Date.ToText([Date], &quot;yyyyMM&quot;)), Int64.Type),
AddYearMonthName = Table.AddColumn(AddYearMonthNum, &quot;Year Month Name&quot;, each Date.ToText([Date], &quot;yyyy-MMM&quot;), type text),
#&quot;Inserted Day&quot; = Table.AddColumn(AddYearMonthName, &quot;Day&quot;, each Date.Day([Date]), Int64.Type),
#&quot;Inserted Day of Week&quot; = Table.AddColumn(#&quot;Inserted Day&quot;, &quot;Day of Week&quot;, each Date.DayOfWeek([Date]), Int64.Type),
#&quot;Inserted Day of Year&quot; = Table.AddColumn(#&quot;Inserted Day of Week&quot;, &quot;Day of Year&quot;, each Date.DayOfYear([Date]), Int64.Type),
#&quot;Inserted Start of Day&quot; = Table.AddColumn(#&quot;Inserted Day of Year&quot;, &quot;Start of Day&quot;, each Date.StartOfDay([Date]), type date),
#&quot;Inserted End of Day&quot; = Table.AddColumn(#&quot;Inserted Start of Day&quot;, &quot;End of Day&quot;, each Date.EndOfDay([Date]), type date),
#&quot;Inserted Day Name&quot; = Table.AddColumn(#&quot;Inserted End of Day&quot;, &quot;Day Name&quot;, each Date.DayOfWeekName([Date]), type text)
in
#&quot;Inserted Day Name&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy Querying!!! Now you have a date table to use for your analysis.&lt;/p&gt;
&lt;p&gt;If you encounter any difficulties or have any questions, feel free to reach out through the comment box. You can connect with me on &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/mubardauda&quot;&gt;Twitter&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://linkedin.com/in/mubardauda&quot;&gt;LinkedIn&lt;/a&gt; where I share my daily activities about data analytics, personal experience, and career life.&lt;/p&gt;
</description>
<category>Power Query</category>
<guid isPermaLink="true">https://coderlegion.com/1884/how-to-create-a-date-table-in-power-query</guid>
<pubDate>Fri, 18 Apr 2025 10:43:44 +0000</pubDate>
</item>
</channel>
</rss>