Tag: syndicated

  • Counting Groups with Window Functions: #SQLNewBlogger

    I looked at row_number() in a previous post. Now I want to build on that and do some counting of rows with COUNT() and the OVER clause. I’ll show how this differs a bit from a normal aggregate.

    Another post for me that is simple and hopefully serves as an example for people trying to get blogging as #SQLNewBloggers. This is also part of a series on Window Functions.

    The Raw Data

    Let’s use AdventureWorks as a sample database. In the Sales.SalesOrderHeader table there are lots of customer orders, each with a Customer ID. I’ll limit my results to these customers, which has a spread of orders:

    WHERE soh.CustomerID IN (11011, 11015, 11019, 11012)

    We’ll use this WHERE clause to help us decide

    Counting Orders

    If I wanted to count the number of orders each customer hasplaced, I can use this code:

    SELECT
       soh.CustomerID
    , COUNT (*) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 )
    GROUP BY soh.CustomerID;

    I see these results:

    2024-10_0175

    We can see that each of these customers has different numbers of orders.  If I want a simple summary, this is the best code. However, what if I want to add other columns?

    Supposed I want to add not only the customer ID, but also the shipdate. I’m wondering when orders were shipped. If I use the code above, I’d need to add this in the column list, and the group by. If I do this, I get this code:

    SELECT
       soh.CustomerID
    , soh.ShipDate
    , COUNT (*) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 )
    GROUP BY
       soh.CustomerID
    , soh.ShipDate;

    And this result:

    2024-10_0176

    The results are cut off, but they repeat with a 1 for each row. The front end can sum these, but it’s easy to make a mistake here. Especially if there are filters.

    With an OVER() clause, my aggregate changes a bit. I would use this code, where I am paritioning, or essentially grouping, the data by the customer ID. I don’t have a group by, so I don’t need to add other fields in two places. Here is the code:

    SELECT
       soh.CustomerID
    , soh.ShipDate
    , COUNT (*) OVER (PARTITION BY soh.CustomerID) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 );

    And the results.

    2024-10_0177

    I have the count repeated, but if I am showing this in the front end, I can hide that column in a table, but I can also access the total count from any row.

    Differences with Group By

    Let’s say I decide to add something else, like the account number and the SalesOrderNumber. If I do this in a GROUP BY, I need to add this to the column list and the group by, as shown here:

    SELECT
       soh.CustomerID
    , soh.AccountNumber
    , soh.SalesOrderNumber
    , soh.ShipDate
    , COUNT (*) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 )
    GROUP BY
       soh.CustomerID
    , soh.ShipDate
    , soh.AccountNumber
    , soh.SalesOrderNumber;
    GO

    The change the Window function is as shown:

    SELECT
       soh.CustomerID
    , soh.AccountNumber
    , soh.SalesOrderNumber
    , soh.ShipDate
    , COUNT (*) OVER (PARTITION BY soh.CustomerID) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 );

    Maintenance is easy, and what’s more, I don’t have to worry about ordering my group by in different ways. If I do care about grouping, then I can alter the partitioning, but often I just want to add other columns without making the code more complex in a second place.

    The results for the group by have the fields, but all 1s in the count again.

    2024-10_0179

    The window function has the counts for each customer.

    2024-10_0178

    Small things, but those points of maintenance can be annoying and they can cause problems. For complex data, the other fields might not group well, or the order of grouping might change what is shown.

    There are more things to be concerned about here, but one of the big things might be a running total, where I count the orders over time. I’d like results like this:

    2024-10_0180

    My window function code is:

    SELECT
       soh.CustomerID
    , soh.AccountNumber
    , soh.SalesOrderNumber
    , soh.ShipDate
    , COUNT (*) OVER (PARTITION BY soh.CustomerID ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS OrderCount
    FROM Sales.SalesOrderHeader AS soh
    WHERE
       soh.CustomerID IN ( 11011, 11015, 11019, 11012 );

    The regular code with group by is this:

    select soh1.customerid, soh1.AccountNumber, soh1.SalesOrderNumber, soh1.ShipDate
    , count(*) 'running_total'
    from sales.salesorderheader soh1
    inner join sales.salesorderheader soh2 on soh2.salesorderid <= soh1.salesorderid
                                        and soh2.customerid = soh1.customerid
    group by soh1.customerid, soh1.AccountNumber, soh1.SalesOrderNumber, soh1.ShipDate
    order by soh1.customerid, soh1.ShipDate

    Not bad, but the big difference is in resources used. The statistics IO below shows the difference. Can you guess which is which?

    2024-10_0183

    Hint, the one using less reads is the OVER() code.

    SQL New Blogger

    Setting up a good scenario is a little tricky, and that took time. I messed with a few data sets that helped explain this to me, and you, in a way that made sense. I have a few other scenarios, which I will write about because an OVER() isn’t magic and it might not be the right choice.

    Those will be other blogs.

    This is a good way to showcase that you understand part of how this works. There’s a whole series to be written on different aspects of how the OVER() clause works. Spending 15-30 minutes each time you experiment helps showcase your knowledge and learning to employers.

    That’s what employers need: experimenting and learning.

  • Monday Monitor Tips: Projecting Disk Space

    One of the things that many DBAs struggle with is managing space across an estate. There might be one or two servers that you watch closely, or that are a constant problem, but it’s easy to run out of space on other systems.

    Redgate Monitor will alert you to low space, but do you want to keep asking SAN admins for more space every week as new systems run out of space? Or do you want to project a number for the year and get that budgeted? Learn how Redgate Monitor can help

    This is part of a series of posts on Redgate Monitor. Click to see the other posts

    An Estate View of Storage

    The estate view of disk usage shows all your disks totaled up and the projections for growth. This looks like the image below on monitor.red-gate.com. This doesn’t seem useful, but I’ve had storage admins come to me in the past asking about budgeting for the next year. How much space will I use?

    2024-09_0139

    The answer is often I don’t know. I’d have to take a very wild guess for them. Now, I’d use this, and maybe pad it slightly, but across lots of systems, we can probably guess on the growth that will be needed. Any one system might not be predictable, but across lots, averages work out.

    Here I can see we’re using 25TB (out of 87TB). Definitely be careful showing this to storage admins, as they often want those to be closer, ubt I can see I’m projected to use 91TB in a year, so I’d need more space. The graph above shows me running out of space in Sept/Oct of 2025.

    Below this I see details from machines and their disks. These show in the same groups I see on other screens. While I can’t easily filter here, I can search from a browser, or export this information. That’s useful for checking on individual systems.

    2024-09_0149

    The other nice thing is I can sort the columns, and if I do this by time until full, I can see the disks that might give me problems soon.

    2024-09_0154

    None of the test systems are likely to be problematic soon, but certainly someone needs to budget for next year.

    Summary

    This is a simple screen, but one that I wish I’d have had in the past. It gives me a lot of information that I rarely need, but information that always requires a lot of effort to compile. What disks are being used by my database servers and what percentage of space is in use.

    In a DBA team, this is the type of data I’d want to glance at every quarter and then make adjustments to prevents issues. Proactive DBAs want a screen just like this.

    Redgate Monitor is a world class monitoring solution for your database estate. Download a trial today and see how it can help you manage your estate more efficiently.

  • A New Word: Feresy

    feresy – n.  the fear that your partner is changing in ways you don’t understand, even though they might be changes for the better, because it forces you to wonder whether your relationship needs a few careful nudges to fall back into balance, or perhaps is still as stable as ever, but involves a person who no longer exists.

    I used to experience feresy, worried that my wife, or even I, were changing in ways that might make us move further apart. Over time, I’ve learned that we both will change, and we have to accept the other will grow and change. They aren’t the same person we married, nor are they someone we can force to change in the way we want.

    However, if there is a balance adjustment needed, we both know we need to communicate to ensure that we maintain a strong partnership. 

    I don’t fear my wife not being the person she was because that person no longer exists.

    From the Dictionary of Obscure Sorrows

  • Using SQL Compare in Read-Only Databases

    Recently a customer asked if SQL Compare and SQL Data Compare can be used with a read-only database as a source. It’s a good questions as I’ve seen some tools that create temp tables or do some other work in a source database, which might cause problems. Certainly someone running SQL Compare against production would want to ensure it works as a read-only application.

    This post will look at SQL Compare with a database set to read-only. I’ll do a second post on a login that only has read authorization.

    This is part of a series of posts on SQL Compare.

    Setup

    I’ve got a couple of databases that I use for Compare demos. In this case, compare5_prod and compare1. The compare5_prod is set to read only, as you see below.

    2024-10_0103

    My connection is as a sysadmin, but that doesn’t override a read-only database. As you can see below, Compare works fine:

    2024-10_0105

    This is because SQL Compare is not writing anything to the database. We read metadata and then process that in-memory on the client before returning the results.

    You can see this also works in SQL Data Compare.

    2024-10_0106

    Summary

    This was a very simple example, but I find that clients always would prefer to see examples already completed and proof that something works when they are evaluating software. Hopefully this helps answer this question.

    SQL Compare is an amazing tool that millions of users have enjoyed for 25 years. If you’ve never tried it, give it an eval today and see what you think.