SQL Server 2022: Improved Performance for String Splitting and Parsing

In SQL Server 2022, Microsoft has introduced significant improvements in string splitting and parsing capabilities, making data manipulation more efficient. This blog explores these enhancements, providing practical examples using the JBDB database, and highlights a business use case to demonstrate the impact of these features.


๐Ÿ“Š Business Use Case: Streamlining Data Analysis

Scenario:

A retail company, “TechShop,” collects customer feedback via online surveys. The responses are stored in a SQL Server database, and each response includes a comma-separated list of keywords describing the customer’s experience. The company wants to analyze these keywords to identify trends and improve its services.

Challenge:

With the previous SQL Server versions, splitting these comma-separated strings into individual keywords for analysis was resource-intensive and time-consuming, especially with large datasets. The goal is to leverage SQL Server 2022’s improved string splitting and parsing features to streamline this process.

๐Ÿ› ๏ธ Key Features and Enhancements

1. STRING_SPLIT with Ordering Support

SQL Server 2022 introduces ordering support for the STRING_SPLIT function, allowing users to retain the order of elements in the original string. This enhancement is crucial for analyses where the sequence of data is significant.

2. Improved Performance

The performance of string splitting operations has been optimized, reducing execution time and resource consumption. This is particularly beneficial for large-scale data processing.

3. Enhanced Parsing Functions

Enhanced parsing functions provide more robust error handling and compatibility with different data types, improving data quality and reducing manual data cleaning efforts.

๐Ÿงฉ Example Demonstration with JBDB Database

Let’s dive into some examples using the JBDB database to showcase these improvements.

Setting Up the JBDB Database

First, we’ll set up a table to store customer feedback:

CREATE TABLE CustomerFeedback (
    FeedbackID INT IDENTITY(1,1) PRIMARY KEY,
    FeedbackText NVARCHAR(MAX)
);

INSERT INTO CustomerFeedback (FeedbackText)
VALUES
('Great service, fast shipping, quality products'),
('Slow delivery, excellent customer support'),
('Fantastic prices, will shop again, good variety'),
('Quality products, quick response time, friendly staff');

CREATE TABLE LargeCustomerFeedback (
    FeedbackID INT IDENTITY(1,1) PRIMARY KEY,
    FeedbackText NVARCHAR(MAX)
);

INSERT INTO LargeCustomerFeedback (FeedbackText)
VALUES
('Great service, fast shipping, quality products'),
('Slow delivery, excellent customer support'),
('Fantastic prices, will shop again, good variety'),
('Quality products, quick response time, friendly staff')
,('Great service1, fast shipping1, quality products1'),
('Slow delivery1, excellent customer support1'),
('Fantastic prices1, will shop again1, good variety1'),
('Quality products1, quick response time1, friendly staff1')
,('Great service2, fast shipping2, quality products2'),
('Slow delivery2, excellent customer support2'),
('Fantastic prices2, will shop again2, good variety2'),
('Quality products2, quick response time2, friendly staff2')
,('Great service3, fast shipping3, quality products3'),
('Slow delivery3, excellent customer support3'),
('Fantastic prices3, will shop again3, good variety3'),
('Quality products3, quick response time3, friendly staff3');

Using STRING_SPLIT with Ordering Support

Previously, STRING_SPLIT did not guarantee the order of elements. In SQL Server 2022, you can specify the order of elements:

SELECT 
    FeedbackID,
    value AS Keyword
FROM 
    CustomerFeedback
    CROSS APPLY STRING_SPLIT(FeedbackText, ',', 1)
ORDER BY 
    FeedbackID, ordinal;

In this query:

  • FeedbackText is split into individual keywords.
  • The ordinal column (optional) provides the order of elements as they appear in the original string.

Improved Performance Demonstration

To demonstrate the performance improvements, let’s compare the execution times for splitting a large dataset in SQL Server 2022 vs. a previous version. For simplicity, assume we have a LargeCustomerFeedback table similar to CustomerFeedback but with millions of rows.

Example Query for Large Dataset

SELECT 
    FeedbackID,
    value AS Keyword
FROM 
    LargeCustomerFeedback
    CROSS APPLY STRING_SPLIT(FeedbackText, ',', 1)
ORDER BY 
    FeedbackID, ordinal;

In practice, SQL Server 2022 processes this operation significantly faster, showcasing its enhanced string handling capabilities.

Counting Keywords from Feedback

To analyze the frequency of keywords mentioned in customer feedback, you can use the following query:

SELECT 
    value AS Keyword,
    COUNT(*) AS Frequency
FROM 
    CustomerFeedback
    CROSS APPLY STRING_SPLIT(FeedbackText, ',', 1)
GROUP BY 
    value
ORDER BY 
    Frequency DESC;

This query splits the feedback text into keywords and counts their occurrences, helping identify common themes or issues mentioned by customers.

Filtering Feedback Containing Specific Keywords

If you want to filter feedback entries containing specific keywords, such as “quality,” you can use:

SELECT 
    FeedbackID,
    FeedbackText
FROM 
    CustomerFeedback
WHERE 
    EXISTS (
        SELECT 1
        FROM STRING_SPLIT(FeedbackText, ',', 1)
        WHERE value = 'quality'
    );

This query finds feedback entries that mention “quality,” allowing the analysis of customer sentiments regarding product quality.

Extracting Unique Keywords

To extract unique keywords from all feedback entries, use the following query:

SELECT DISTINCT 
    value AS UniqueKeyword
FROM 
    CustomerFeedback
    CROSS APPLY STRING_SPLIT(FeedbackText, ',', 1);

This query provides a list of all unique keywords, helping identify the range of topics covered in customer feedback.

๐Ÿ“ˆ Business Impact

By leveraging SQL Server 2022’s improved string splitting and parsing features, TechShop can:

  1. Accelerate Data Processing: The company can quickly analyze large volumes of customer feedback, allowing for timely insights into customer sentiment and trends.
  2. Improve Data Accuracy: The new features reduce the need for manual data cleaning and error handling, ensuring more accurate analysis.
  3. Enhance Customer Experience: By understanding customer feedback more efficiently, TechShop can make informed decisions to improve its services, leading to higher customer satisfaction and retention.

๐ŸŽ‰ Conclusion

SQL Server 2022’s advancements in string splitting and parsing offer substantial benefits for data-driven businesses. The enhancements in performance, ordering support, and robust error handling make it easier and faster to analyze complex datasets. For companies like TechShop, these features enable better customer insights and more agile decision-making.

๐Ÿ’ก Tip: Always test these features with your specific data and workload to fully understand the performance benefits and implementation considerations.

For more tutorials and tips on  SQL Server, including performance tuning and  database management, be sure to check out our JBSWiki YouTube channel.

Thank You,
Vivek Janakiraman

Disclaimer:
The views expressed on this blog are mine alone and do not reflect the views of my company or anyone else. All postings on this blog are provided โ€œAS ISโ€ with no warranties, and confers no rights.

SQL Server 2022: Unleashing the Power of the GENERATE_SERIES Function

In SQL Server 2022, the introduction of the GENERATE_SERIES function marks a significant enhancement, empowering developers and analysts with a flexible and efficient way to generate sequences of numbers. This feature, akin to similar functions in other database systems, simplifies tasks involving sequence generation, such as creating time series data, generating test data, and more.

In this blog, we’ll explore the GENERATE_SERIES function in detail, using the JBDB database to demonstrate its capabilities. We’ll start with a practical business use case, followed by a comprehensive guide on how to use the function. Let’s dive in! ๐ŸŒŸ

Business Use Case: Sales Forecasting ๐Ÿ“ˆ

Imagine you are working for a retail company, and your task is to generate a sales forecast for the next year. You have historical sales data and need to project future sales based on trends. A crucial step in this process is to create a series of dates representing each day of the next year, which will serve as the basis for the forecast.

The GENERATE_SERIES function can be a game-changer here, allowing you to quickly generate a range of dates without resorting to complex loops or recursive queries.

Introducing the GENERATE_SERIES Function ๐Ÿ› ๏ธ

The GENERATE_SERIES function generates a series of numbers or dates. Its syntax is straightforward:

GENERATE_SERIES(start, stop, step)
  • start: The starting value of the sequence.
  • stop: The ending value of the sequence.
  • step: The increment value between each number in the series.

Let’s see this in action with some practical examples!

Example 1: Basic Numeric Series ๐Ÿ”ข

To generate a series of numbers from 1 to 10:

SELECT value
FROM GENERATE_SERIES(1, 10, 1);

Example 2: Date Series for Forecasting ๐Ÿ“…

To generate a series of dates for each day of the next year, starting from January 1, 2023:

SELECT CAST(value AS DATE) AS ForecastDate
FROM GENERATE_SERIES('2023-01-01', '2023-12-31', 1);

Generating a Series of Dates Using a CTE ๐Ÿ“…

Since GENERATE_SERIES supports numeric sequences only, we use a recursive CTE to generate a series of dates. Hereโ€™s how to create a series of dates for the year 2023:

-- Create a recursive CTE to generate a series of dates
WITH DateSeries AS (
    -- Anchor member: start date
    SELECT CAST('2023-01-01' AS DATE) AS ForecastDate
    UNION ALL
    -- Recursive member: add one day to the previous date
    SELECT DATEADD(DAY, 1, ForecastDate)
    FROM DateSeries
    WHERE ForecastDate < '2023-12-31'
)
-- Query to select the generated dates
SELECT ForecastDate
FROM DateSeries
OPTION (MAXRECURSION 0); -- Remove recursion limit

Implementing the Use Case: Sales Forecasting ๐Ÿ“Š

Let’s apply the GENERATE_SERIES function to our sales forecasting scenario. Suppose we have a table Sales in the JBDB database with historical sales data. Our goal is to project future sales for each day of the next year.

Step 1: Creating the JBDB and Sales Table ๐Ÿ—๏ธ

First, we create the JBDB database and the Sales table:

CREATE DATABASE JBDB;
GO

USE JBDB;
GO

CREATE TABLE Sales (
    SaleDate DATE,
    Amount DECIMAL(10, 2)
);

Step 2: Inserting Historical Data ๐Ÿ“ฅ

Next, let’s insert some historical data into the Sales table:

INSERT INTO Sales (SaleDate, Amount)
VALUES
('2022-01-01', 100.00),
('2022-01-02', 150.00),
('2022-01-03', 200.00),
-- Additional data...
('2022-12-31', 250.00);

Step 3: Generating Future Dates and Forecasting ๐Ÿ“…๐Ÿ”ฎ

Now, we use GENERATE_SERIES to generate future dates and join it with our historical data to create a sales forecast:

-- Generate a series of future dates
WITH DateSeries AS (
    SELECT CAST('2023-01-01' AS DATE) AS ForecastDate
    UNION ALL
    SELECT DATEADD(DAY, 1, ForecastDate)
    FROM DateSeries
    WHERE ForecastDate < '2023-12-31'
),
-- Combine with historical sales data
SalesForecast AS (
    SELECT
        f.ForecastDate,
        ISNULL(s.Amount, 0) AS HistoricalAmount
    FROM
        DateSeries f
        LEFT JOIN Sales s ON f.ForecastDate = s.SaleDate
)
-- Project future sales
SELECT
    ForecastDate,
    HistoricalAmount,
    -- Simple projection logic (for demonstration)
    HistoricalAmount * 1.05 AS ProjectedAmount
FROM SalesForecast
OPTION (MAXRECURSION 0); -- Remove recursion limit

In this query:

  • We generate a series of dates for the year 2023 using GENERATE_SERIES.
  • We join these dates with the historical sales data to create a comprehensive sales forecast.
  • A simple projection logic is applied, assuming a 5% increase in sales.

Generate a Series of Numbers with Custom Step Size

Generate a sequence of numbers from 1 to 50 with a step size of 5:

-- Generate a sequence of numbers with a custom step size
SELECT value
FROM GENERATE_SERIES(1, 50, 5);

Generate a Series of Dates with Custom Step Size

Generate a series of dates from today to 30 days into the future with a step size of 5 days:

-- Generate a series of dates with a custom step size (5 days)
WITH DateSeries AS (
    SELECT DATEADD(DAY, value * 5, CAST(GETDATE() AS DATE)) AS ForecastDate
    FROM GENERATE_SERIES(0, 6, 1) -- 0 to 6 will generate 7 dates
)
SELECT ForecastDate
FROM DateSeries;

Generate a Series of Random Numbers

Generate a series of random numbers between 1 and 100:

-- Generate a series of random numbers between 1 and 100
SELECT ABS(CHECKSUM(NEWID())) % 100 + 1 AS RandomNumber
FROM GENERATE_SERIES(1, 10, 1); -- Generate 10 random numbers

Generate a Series of Time Intervals

Generate a series of time intervals (every 15 minutes) for one hour:

-- Generate a series of time intervals (15 minutes) for one hour
WITH TimeSeries AS (
    SELECT DATEADD(MINUTE, value * 15, CAST('2024-01-01 00:00:00' AS DATETIME)) AS TimeStamp
    FROM GENERATE_SERIES(0, 3, 1) -- 0 to 3 will generate 4 intervals
)
SELECT TimeStamp
FROM TimeSeries;

Generate a Series of Sequential IDs

Generate a series of sequential IDs from 1001 to 1010:

-- Generate a sequence of sequential IDs
SELECT value + 1000 AS SequentialID
FROM GENERATE_SERIES(1, 10, 1);

Generate a Series of Numeric Values with Non-Uniform Steps

Generate a series of numbers with varying steps (e.g., 1, 2, 4, 8, …):

-- Generate a series of numbers with varying steps (powers of 2)
WITH NumberSeries AS (
    SELECT 1 AS value
    UNION ALL
    SELECT value * 2
    FROM NumberSeries
    WHERE value < 64
)
SELECT value
FROM NumberSeries
OPTION (MAXRECURSION 0);

Generate a Series of Dates with Monthly Intervals

Generate a series of dates with a monthly interval for one year:

-- Generate a series of dates with monthly intervals for one year
WITH MonthSeries AS (
    SELECT DATEADD(MONTH, value, CAST('2024-01-01' AS DATE)) AS MonthStart
    FROM GENERATE_SERIES(0, 11, 1) -- 0 to 11 will generate 12 months
)
SELECT MonthStart
FROM MonthSeries;

Generate a Series of Numbers and Calculate Cumulative Sum

Generate a series of numbers and calculate their cumulative sum:

-- Generate a series of numbers and calculate the cumulative sum
WITH NumberSeries AS (
    SELECT value
    FROM GENERATE_SERIES(1, 10, 1)
),
CumulativeSum AS (
    SELECT
        value,
        SUM(value) OVER (ORDER BY value) AS CumulativeSum
    FROM NumberSeries
)
SELECT value, CumulativeSum
FROM CumulativeSum;

Generate a Series of Custom Random Dates

Generate a series of random dates within a specific range:

— Generate a series of random dates within a specific range
WITH RandomDates AS (
SELECT DATEADD(DAY, ABS(CHECKSUM(NEWID())) % 365, CAST(‘2024-01-01’ AS DATE)) AS RandomDate
FROM GENERATE_SERIES(1, 10, 1) — Generate 10 random dates
)
SELECT RandomDate
FROM RandomDates;

Generate a Series of Numbers and Create Custom Labels

Generate a series of numbers and create custom labels:

— Generate a series of numbers and create custom labels
SELECT value AS Number, ‘Label_’ + CAST(value AS VARCHAR(10)) AS CustomLabel
FROM GENERATE_SERIES(1, 10, 1);

Conclusion ๐ŸŒŸ

The GENERATE_SERIES function in SQL Server 2022 is a versatile tool that can significantly simplify the generation of sequences, whether for numeric ranges or date series. Its applications range from creating time series data for analytics to generating test data for development and testing purposes.

By leveraging GENERATE_SERIES, businesses can streamline their data workflows, enhance forecasting accuracy, and improve decision-making processes. Whether you’re a database administrator, developer, or data analyst, this function is a valuable addition to your SQL toolkit.

Feel free to experiment with GENERATE_SERIES and explore its potential in your projects! ๐ŸŽ‰

For more tutorials and tips on SQL Server, including performance tuning and database management, be sure to check out our JBSWiki YouTube channel.

Thank You,
Vivek Janakiraman

Disclaimer:
The views expressed on this blog are mine alone and do not reflect the views of my company or anyone else. All postings on this blog are provided โ€œAS ISโ€ with no warranties, and confers no rights.

SQL Server 2022 STRING_SPLIT Enhancements: A Deep Dive with JBDB Database

In SQL Server 2022, the STRING_SPLIT function has been enhanced, making it a powerful tool for parsing and handling delimited strings. This blog will provide an exhaustive overview of these enhancements, using the JBDB database for demonstrations. We’ll explore a detailed business use case, delve into the new features, and provide T-SQL queries for you to practice and master the updated STRING_SPLIT function. Let’s dive in! ๐ŸŒŠ


Business Use Case: Customer Preferences Analysis ๐Ÿ›๏ธ

Imagine you’re working for an e-commerce company that tracks customer preferences for various product categories. Each customer’s preference is stored as a comma-separated string in the database. Your task is to analyze these preferences to offer personalized recommendations and optimize the marketing strategy.

For instance, the data might look like this:

  • Customer 1: Electronics,Books,Toys
  • Customer 2: Groceries,Fashion,Electronics
  • Customer 3: Books,Beauty,Fashion

With the enhancements in STRING_SPLIT in SQL Server 2022, you can efficiently parse these strings and analyze the data. Let’s explore how!


STRING_SPLIT Enhancements in SQL Server 2022 ๐Ÿš€

In SQL Server 2022, STRING_SPLIT has been enhanced to include:

  1. Ordinal Output: A new parameter, ordinal, can now be specified to include the position of each substring in the original string.
  2. Improved Performance: Enhanced indexing capabilities for better performance in large datasets.

Syntax:

STRING_SPLIT ( string, separator [, enable_ordinal ] )
  • string: The input string to be split.
  • separator: The delimiter character.
  • enable_ordinal: Optional; specifies whether to include the ordinal position of each substring (0 or 1).

Example 1: Basic Usage ๐ŸŒŸ

Let’s start with a simple example to see the new ordinal feature in action.

Setup:

USE JBDB;
GO

CREATE TABLE CustomerPreferences (
    CustomerID INT PRIMARY KEY,
    Preferences VARCHAR(100)
);

INSERT INTO CustomerPreferences (CustomerID, Preferences)
VALUES
(1, 'Electronics,Books,Toys'),
(2, 'Groceries,Fashion,Electronics'),
(3, 'Books,Beauty,Fashion');
GO

Query with STRING_SPLIT:

SELECT CustomerID, value, ordinal
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1);

This output shows the customer preferences along with their order of appearance. The ordinal column is a new addition in SQL Server 2022, providing valuable information about the sequence of items.

Example 2: Analyzing Preferences ๐Ÿ”

Now, let’s say we want to find out the most popular categories among all customers.

Query to Find Most Popular Categories:

SELECT value AS Category, COUNT(*) AS Count
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
GROUP BY value
ORDER BY Count DESC;

From the output, we can see that ‘Electronics’, ‘Books’, and ‘Fashion’ are the most popular categories. This data can be used to tailor marketing campaigns and inventory management.

Extracting Categories Based on Position:

  • Find customers whose second preference is ‘Fashion’:
SELECT CustomerID
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
WHERE ordinal = 2 AND value = 'Fashion';

Counting Unique Categories:

  • Count the number of unique categories preferred by customers:
SELECT COUNT(DISTINCT value) AS UniqueCategories
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1);

Combining STRING_SPLIT with Other Functions:

  • Find the length of each preference category string:
SELECT CustomerID, value, LEN(value) AS Length
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1);

Analyzing Preferences by Customer:

  • Count the number of preferences each customer has:
SELECT CustomerID, COUNT(*) AS PreferenceCount
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
GROUP BY CustomerID;

Extracting Values by Ordinal Position:

  • Identify customers whose first preference is ‘Electronics’:
SELECT CustomerID
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
WHERE ordinal = 1 AND value = 'Electronics';

Finding Specific Ordinal Positions:

  • Retrieve all customers whose third preference includes ‘Books’:
SELECT CustomerID
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
WHERE ordinal = 3 AND value = 'Books';

Filtering Based on Multiple Conditions:

  • Find customers who have ‘Books’ in any position and ‘Fashion’ as the last preference:
SELECT CustomerID
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
GROUP BY CustomerID
HAVING SUM(CASE WHEN value = 'Books' THEN 1 ELSE 0 END) > 0
   AND MAX(CASE WHEN value = 'Fashion' THEN ordinal ELSE 0 END) = COUNT(*);

Analyzing Distribution of Preferences:

  • Determine the number of customers who have each category as their first preference:
SELECT value AS FirstPreference, COUNT(*) AS Count
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
WHERE ordinal = 1
GROUP BY value
ORDER BY Count DESC;

Combining STRING_SPLIT with String Functions:

  • Find the customers with the longest category name in their preferences:
SELECT CustomerID, value, LEN(value) AS Length
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
ORDER BY Length DESC;

Using STRING_SPLIT for Data Transformation:

  • Convert customer preferences into a single concatenated string with a different delimiter:
SELECT CustomerID, STRING_AGG(value, '|') AS ConcatenatedPreferences
FROM CustomerPreferences
CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
GROUP BY CustomerID;

Analyzing Preference Patterns:

  • Find the most common pattern of the first two preferences:
WITH FirstTwoPreferences AS (
    SELECT CustomerID, STRING_AGG(value, ',') WITHIN GROUP (ORDER BY ordinal) AS Pattern
    FROM CustomerPreferences
    CROSS APPLY STRING_SPLIT(Preferences, ',', 1)
    WHERE ordinal <= 2
    GROUP BY CustomerID
)
SELECT Pattern, COUNT(*) AS Count
FROM FirstTwoPreferences
GROUP BY Pattern
ORDER BY Count DESC;

Conclusion ๐Ÿ

The enhancements in SQL Server 2022’s STRING_SPLIT function, particularly the introduction of the ordinal parameter, provide powerful tools for handling and analyzing delimited strings. Whether you’re working with customer data, logs, or any form of delimited information, these enhancements can streamline your processes and deliver valuable insights.

Happy querying! ๐Ÿ˜„

For more tutorials and tips on SQL Server, including performance tuning and database management, be sure to check out our JBSWiki YouTube channel.

Thank You,
Vivek Janakiraman

Disclaimer:
The views expressed on this blog are mine alone and do not reflect the views of my company or anyone else. All postings on this blog are provided โ€œAS ISโ€ with no warranties, and confers no rights.