Monday, November 15, 2010

Crosstab, Rotate, Pivot, Normalize

The "Crosstab, Rotate, Pivot" article from earlier this year should have been named "Crosstab, Rotate, Pivot, Denormalize" because it showed how to take a perfectly nice table like this

and muck it up to look like this
without hard-coding any of the data values in the SQL.

What about going the other way?

What if you have a fat squat denormalized table with a bazillion columns
and you want to turn it into a tall skinny table with a bazillion rows?
And then (for bonus points) what if you wanted to keep rotating to get a different fat squat version like this?
First things first; here's the first fat squat table:
1
<br>--------------------------------------------------------------------------------<br>-- Step 1: Initialize data.<br><br>CREATE TABLE t1 (<br>   c1              VARCHAR ( 10 ) NOT NULL,<br>   Ford_count      INTEGER NOT NULL, <br>   Hyundai_count   INTEGER NOT NULL, <br>   Honda_count     INTEGER NOT NULL, <br>   Chevrolet_count INTEGER NOT NULL,<br>   PRIMARY KEY ( c1 ) );<br><br>INSERT t1 VALUES ( 'AZ', 5000, 5000, 1000, 3000 );<br>INSERT t1 VALUES ( 'CA', 1000, 2000, 9000, 7000 );<br>INSERT t1 VALUES ( 'FL', 9000, 7000, 2000, 1000 );<br>INSERT t1 VALUES ( 'MA', 2000, 6000, 5000, 3000 );<br>INSERT t1 VALUES ( 'NY', 4000, 5000, 1000, 6000 );<br>COMMIT;<br>
Here's the tall skinny table:
1
<br>CREATE TABLE t1_normalized (<br>   c1              VARCHAR ( 10 ) NOT NULL,<br>   c2              VARCHAR ( 128 ) NOT NULL,<br>   c3              INTEGER NOT NULL, <br>   PRIMARY KEY ( c1, c2 ) );<br>
Here's the code that fills the tall skinny table (Step 2) and then rotates it again to create the second fat squat table (Step 3):
1
<br>BEGIN<br><br>DECLARE @sql LONG VARCHAR;<br><br>--------------------------------------------------------------------------------<br>-- Step 2: Normalize table.<br><br>SELECT STRING ( <br>          'INSERT t1_normalized \x0d\x0a',<br>          LIST ( <br>             STRING ( <br>                'SELECT c1, \x0d\x0a',<br>                '       ''', SYSCOLUMN.column_name, ''',\x0d\x0a',<br>                '       ', SYSCOLUMN.column_name, '\x0d\x0a',<br>                '  FROM ', SYSTABLE.table_name ),<br>             '\x0d\x0aUNION ALL \x0d\x0a'<br>             ORDER BY SYSCOLUMN.column_id ) )<br>  INTO @sql<br>  FROM SYSCOLUMN <br>          INNER JOIN SYSTABLE <br>                  ON SYSTABLE.table_id = SYSCOLUMN.table_id <br> WHERE SYSTABLE.table_name = 't1'<br>   AND SYSCOLUMN.column_name LIKE '%?_count' ESCAPE '?';<br><br>SELECT @sql; -- for display<br><br>EXECUTE IMMEDIATE @sql;<br><br>--------------------------------------------------------------------------------<br>-- Step 3: Pivot c1 values into columns.<br><br>SELECT STRING ( <br>          'SELECT c2',<br>          LIST ( <br>             STRING ( <br>                ',\x0d\x0a       SUM ( ( IF t1_normalized.c1 = ''',<br>                t1_distinct.c1,<br>                ''' THEN 1 ELSE 0 ENDIF ) * t1_normalized.c3 ) AS "',<br>                t1_distinct.c1,<br>                '"' ),<br>             ''<br>             ORDER BY t1_distinct.c1 ),<br>          '\x0d\x0a  INTO #t1_pivot',<br>          '\x0d\x0a  FROM t1_normalized',<br>          '\x0d\x0a GROUP BY t1_normalized.c2' ) <br>  INTO @sql<br>  FROM ( SELECT DISTINCT c1<br>           FROM t1_normalized ) AS t1_distinct;<br><br>SELECT @sql; -- for display<br><br>EXECUTE IMMEDIATE @sql;<br><br>SELECT * FROM t1 ORDER BY c1;                  -- original data, for checking<br>SELECT * FROM t1_normalized ORDER BY c1, c2;   -- normalized data, for checking<br>SELECT * FROM #t1_pivot ORDER BY c2;           -- pivot table<br><br>END;<br>
Step 2 is the interesting part: it builds a SQL statement dynamically, at runtime, and then uses the magic EXECUTE IMMEDIATE feature to execute that statement. EXECUTE IMMEDIATE isn't a new feature, it's been around forever, and although the code in this article has only been tested on SQL Anywhere 11.0.1 and 12.0.0 I'm pretty sure it works on older versions like 9 and 10, maybe even earlier.

The code on lines 19 through 23 looks in the SYSTABLE and SYSCOLUMN system tables for all the "_count" columns in table "t1". (Yes, this code depends on the being able to identify the columns of interest by how they are named: see the LIKE predicate on line 23.)
08.SELECT STRING (
09. 'INSERT t1_normalized \x0d\x0a',
10. LIST (
11. STRING (
12. 'SELECT c1, \x0d\x0a',
13. ' ''', SYSCOLUMN.column_name, ''',\x0d\x0a',
14. ' ', SYSCOLUMN.column_name, '\x0d\x0a',
15. ' FROM ', SYSTABLE.table_name ),
16. '\x0d\x0aUNION ALL \x0d\x0a'
17. ORDER BY SYSCOLUMN.column_id ) )
18. INTO @sql
19. FROM SYSCOLUMN
20. INNER JOIN SYSTABLE
21. ON SYSTABLE.table_id = SYSCOLUMN.table_id
22. WHERE SYSTABLE.table_name = 't1'
23. AND SYSCOLUMN.column_name LIKE '%?_count' ESCAPE '?';
24.
25.SELECT @sql; -- for display
26.
27.EXECUTE IMMEDIATE @sql;
The code on lines 8 through 18 builds a SQL statement in a string, and puts that string in the local LONG VARCHAR variable @sql.

The value placed in @sql consists of an 'INSERT...' (line 9) followed by a LIST (line 10) of 'SELECT...' statements (lines 12 through 15) separated by the 'UNION ALL' operator (line 16). The STRING() and LIST() functions are magic too, just like EXECUTE IMMEDIATE... all well worth learning.

The LIST - ORDER BY on line 17 doesn't affect the final outcome, but it is nice to have the generated SELECTs appear in the same order as the columns appear in the original fat squat table.

Confused yet?

Maybe it will help to see what gets put in @sql; an INSERT statement which creates one row in t1_normalized for every column in t1:
1
<br>INSERT t1_normalized <br>SELECT c1, <br>       'Ford_count',<br>       Ford_count<br>  FROM t1<br>UNION ALL <br>SELECT c1, <br>       'Hyundai_count',<br>       Hyundai_count<br>  FROM t1<br>UNION ALL <br>SELECT c1, <br>       'Honda_count',<br>       Honda_count<br>  FROM t1<br>UNION ALL <br>SELECT c1, <br>       'Chevrolet_count',<br>       Chevrolet_count<br>  FROM t1<br>

Here are the tables again; first, the fat squat input "FROM t1":
...and the tall skinny output "INSERT t1_normalized":
Oh, by the way... the code in Step 3 uses pretty much the same technique shown in Crosstab, Rotate, Pivot to produce the rotated-again fat squat table:

Does it work in the real world?

If you have the impression I sit around all day coding "SELECT FROM t1", let me set the record straight: I own and maintain some of the nastiest real-world code that's ever been created. And it's in that real world where the real problems arise, like the need to normalize and denormalize data to make it possible for the inevitable Queries From Hell to run in finite time. Necessity is the mother of Invention (although I do have to admit, it does sound pompous to use the word "invention" in a sentence :)

OK, so here's some real code, warts and all, the horribly denormalized table that supports the "Peaks since" line in the Foxhound database monitor:



Truly fat, truly squat:
1
<br>CREATE TABLE rroad_peaks (<br><br>   -- *****************************************************************<br>   -- ***** THIS TABLE IS A CANDIDATE FOR POST-SETUP DATA UPGRADE *****<br>   -- *****************************************************************<br><br>   sampling_id                               UNSIGNED INTEGER NOT NULL,<br>   peaks_calculated_to_sample_set_number     UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peaks_calculated_after                    TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,<br>   peaks_calculated_after_sample_set_number  UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   earliest_preserved_sample_set_number      UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_sample_elapsed_msec               BIGINT NOT NULL DEFAULT 0,<br>   peak_canarian_query_elapsed_msec       BIGINT NOT NULL DEFAULT 0, <br>   peak_ActiveReq                         BIGINT NOT NULL DEFAULT 0,<br>   peak_CheckpointUrgency                 BIGINT NOT NULL DEFAULT 0,<br>   peak_interval_Chkpt                    BIGINT NOT NULL DEFAULT 0,<br>   peak_ConnCount                         BIGINT NOT NULL DEFAULT 0,<br>   peak_CurrIO                            BIGINT NOT NULL DEFAULT 0,<br>   peak_DBFileFragments                   BIGINT NOT NULL DEFAULT 0,<br>   peak_LockCount                         BIGINT NOT NULL DEFAULT 0,<br>   peak_MultiProgrammingLevel             BIGINT NOT NULL DEFAULT 0,<br>   peak_RecoveryUrgency                   BIGINT NOT NULL DEFAULT 0,<br>   peak_UnschReq                          BIGINT NOT NULL DEFAULT 0,<br>   peak_executing_connection_count        BIGINT NOT NULL DEFAULT 0,<br>   peak_idle_connection_count             BIGINT NOT NULL DEFAULT 0,<br>   peak_waiting_connection_count          BIGINT NOT NULL DEFAULT 0,<br>   peak_total_blocked_connection_count    BIGINT NOT NULL DEFAULT 0,<br>   peak_total_temporary_file_bytes        BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Bytes                        DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_Disk                         DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_BytesReceived                DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_BytesSent                    DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_CachePanics                  DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_CacheSatisfaction                 DECIMAL ( 30, 6 ) NOT NULL DEFAULT 1.0, -- a ratio, with the smallest value defined as the "peak"<br>   peak_rate_DiskRead                     DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_DiskWrite                    DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_FullCompare                  DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_IndAdd                       DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_IndLookup                    DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_IndSatisfaction                   DECIMAL ( 30, 6 ) NOT NULL DEFAULT 1.0, -- a ratio, with the smallest value defined as the "peak"<br>   peak_rate_LogWrite                     DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_cpu_percentage_string             VARCHAR ( 10 ) NOT NULL DEFAULT '',<br>   peak_cpu_percentage_number             DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_QueryLowMemoryStrategy       DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_Req                          DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_Commit                       DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_rate_Rlbk                         DECIMAL ( 30, 6 ) NOT NULL DEFAULT 0.0,<br>   peak_sample_elapsed_msec_sample_set_number               UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_canarian_query_elapsed_msec_sample_set_number       UNSIGNED BIGINT NOT NULL DEFAULT 0, <br>   peak_ActiveReq_sample_set_number                         UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_CheckpointUrgency_sample_set_number                 UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_interval_Chkpt_sample_set_number                    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_ConnCount_sample_set_number                         UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_CurrIO_sample_set_number                            UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_DBFileFragments_sample_set_number                   UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_LockCount_sample_set_number                         UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_MultiProgrammingLevel_sample_set_number             UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_RecoveryUrgency_sample_set_number                   UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_UnschReq_sample_set_number                          UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_executing_connection_count_sample_set_number        UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_idle_connection_count_sample_set_number             UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_waiting_connection_count_sample_set_number          UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_total_blocked_connection_count_sample_set_number    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_total_temporary_file_bytes_sample_set_number        UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Bytes_sample_set_number                        UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Disk_sample_set_number                         UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_BytesReceived_sample_set_number                UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_BytesSent_sample_set_number                    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_CachePanics_sample_set_number                  UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_CacheSatisfaction_sample_set_number                 UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_DiskRead_sample_set_number                     UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_DiskWrite_sample_set_number                    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_FullCompare_sample_set_number                  UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_IndAdd_sample_set_number                       UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_IndLookup_sample_set_number                    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_IndSatisfaction_sample_set_number                   UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_LogWrite_sample_set_number                     UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_cpu_percentage_sample_set_number                    UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_QueryLowMemoryStrategy_sample_set_number       UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Req_sample_set_number                          UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Commit_sample_set_number                       UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   peak_rate_Rlbk_sample_set_number                         UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   PRIMARY KEY ( sampling_id ) );<br>

Here's the code to normalize the "_sample_set_number" columns into a tall, skinny table:
1
<br>BEGIN<br><br>DECLARE @sql LONG VARCHAR;<br><br>DECLARE LOCAL TEMPORARY TABLE normalized_peaks (<br>   sampling_id        UNSIGNED INTEGER NOT NULL,<br>   column_name        VARCHAR ( 128 ) NOT NULL,<br>   sample_set_number  UNSIGNED BIGINT NOT NULL DEFAULT 0,<br>   PRIMARY KEY ( sampling_id, column_name ) );<br><br>SELECT STRING ( <br>          'INSERT normalized_peaks \x0d\x0a',<br>          LIST ( <br>             STRING ( <br>                'SELECT sampling_id, \x0d\x0a',<br>                '       ''', SYSCOLUMN.column_name, ''',\x0d\x0a',<br>                '       ', SYSCOLUMN.column_name, '\x0d\x0a',<br>                '  FROM ', SYSTABLE.table_name ),<br>             '\x0d\x0aUNION ALL \x0d\x0a'<br>             ORDER BY SYSCOLUMN.column_id ) )<br>  INTO @sql<br>  FROM SYSCOLUMN <br>          INNER JOIN SYSTABLE <br>                  ON SYSTABLE.table_id = SYSCOLUMN.table_id <br> WHERE SYSTABLE.table_name = 'rroad_peaks'<br>   AND SYSCOLUMN.column_name LIKE '%?_sample_set_number' ESCAPE '?';<br><br>SELECT @sql; -- for display<br><br>EXECUTE IMMEDIATE @sql;<br><br>SELECT * FROM rroad_peaks ORDER BY sampling_id;<br>SELECT * FROM normalized_peaks ORDER BY sampling_id, column_name;<br><br>END;<br>

Here's what the normalized table looks like:
And just to drive the point home, here's the answer to the question "Why go to all that trouble with EXECUTE IMMEDIATE blah blah, why not just hand-code the solution?"

The answer is, the rroad_peaks table is subject to change (especially new columns) and the normalization logic is just one more piece of code that does NOT have to change along with it; i.e., this is the generated INSERT, this is the code that doesn't have to be maintained:
1
<br>INSERT normalized_peaks <br>SELECT sampling_id, <br>       'peaks_calculated_to_sample_set_number',<br>       peaks_calculated_to_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peaks_calculated_after_sample_set_number',<br>       peaks_calculated_after_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'earliest_preserved_sample_set_number',<br>       earliest_preserved_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_sample_elapsed_msec_sample_set_number',<br>       peak_sample_elapsed_msec_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_canarian_query_elapsed_msec_sample_set_number',<br>       peak_canarian_query_elapsed_msec_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_ActiveReq_sample_set_number',<br>       peak_ActiveReq_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_CheckpointUrgency_sample_set_number',<br>       peak_CheckpointUrgency_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_interval_Chkpt_sample_set_number',<br>       peak_interval_Chkpt_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_ConnCount_sample_set_number',<br>       peak_ConnCount_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_CurrIO_sample_set_number',<br>       peak_CurrIO_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_DBFileFragments_sample_set_number',<br>       peak_DBFileFragments_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_LockCount_sample_set_number',<br>       peak_LockCount_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_MultiProgrammingLevel_sample_set_number',<br>       peak_MultiProgrammingLevel_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_RecoveryUrgency_sample_set_number',<br>       peak_RecoveryUrgency_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_UnschReq_sample_set_number',<br>       peak_UnschReq_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_executing_connection_count_sample_set_number',<br>       peak_executing_connection_count_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_idle_connection_count_sample_set_number',<br>       peak_idle_connection_count_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_waiting_connection_count_sample_set_number',<br>       peak_waiting_connection_count_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_total_blocked_connection_count_sample_set_number',<br>       peak_total_blocked_connection_count_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_total_temporary_file_bytes_sample_set_number',<br>       peak_total_temporary_file_bytes_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_Bytes_sample_set_number',<br>       peak_rate_Bytes_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_Disk_sample_set_number',<br>       peak_rate_Disk_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_BytesReceived_sample_set_number',<br>       peak_rate_BytesReceived_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_BytesSent_sample_set_number',<br>       peak_rate_BytesSent_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_CachePanics_sample_set_number',<br>       peak_rate_CachePanics_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_CacheSatisfaction_sample_set_number',<br>       peak_CacheSatisfaction_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_DiskRead_sample_set_number',<br>       peak_rate_DiskRead_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_DiskWrite_sample_set_number',<br>       peak_rate_DiskWrite_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_FullCompare_sample_set_number',<br>       peak_rate_FullCompare_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_IndAdd_sample_set_number',<br>       peak_rate_IndAdd_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_IndLookup_sample_set_number',<br>       peak_rate_IndLookup_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_IndSatisfaction_sample_set_number',<br>       peak_IndSatisfaction_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_LogWrite_sample_set_number',<br>       peak_rate_LogWrite_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_cpu_percentage_sample_set_number',<br>       peak_cpu_percentage_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_QueryLowMemoryStrategy_sample_set_number',<br>       peak_rate_QueryLowMemoryStrategy_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_Req_sample_set_number',<br>       peak_rate_Req_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_Commit_sample_set_number',<br>       peak_rate_Commit_sample_set_number<br>  FROM rroad_peaks<br>UNION ALL <br>SELECT sampling_id, <br>       'peak_rate_Rlbk_sample_set_number',<br>       peak_rate_Rlbk_sample_set_number<br>  FROM rroad_peaks<br>

No comments: