M81

Welcoming the IBM Community

sql

Stretch Imagination with SQL Part1

4.9
(9)

Scenario

Let’s take a simple query like.

SQL

select * from qsys2.SYSTEM_STATUS_INFO
SQL

It gives quite useful information, right?  In fact, 109 columns of information that I have to scroll through all right through the screen.

and so forth.

Now, what if I want to track these metrics, say over a dimension of time, more easily?

I have at my disposal quite a few options if I stretch my imagination, right?

  1. Store all these 109 columns in my own version of a table with a time dimension, possibly the easiest, but where is the fun in that?
  2. Perhaps build a view of only the few columns I need and store it in a table-like structure with time. However, this could become cumbersome to change, if I need a new value added, by dropping and recreating the view for each value and possibly having to wrangle some type elements to my resulting table as well.
  3. What if I consider a pivot table view of the metrics of what I am interested in, with a date or time dimension?

Thinking most of the time about how I can use SQL to make my life easier, I decided to use option 3, even if it might be a bit more challenging than what I initially admitted, but with a great learning experience.

My Approach

One of the things I learned from other frameworks is that NAME / VALUE pairs like in JSON make life so much easier, especially when things like arrays are involved for viewing on those web widget things.

I also know that I have the AI tool under my belt to help me do some heavy lifting. I think I am going to use this with my chosen option 3.

Now I know this table has 109 columns, and making them in NAME / VALUE pairs might be challenging, right?

Not really, let’s do it magically with SQL.

Let us break apart all the columns to see what we will be dealing with here :

SQL

--- Expanded Table columns
SELECT TOTAL_JOBS_IN_SYSTEM,
       MAXIMUM_JOBS_IN_SYSTEM,
       ACTIVE_JOBS_IN_SYSTEM,
       INTERACTIVE_JOBS_IN_SYSTEM,
       JOBS_SIGNED_ON,
       JOBS_DISCONNECTED,
       JOBS_SUSPENDED_BY_SYSREQ,
       JOBS_SUSPENDED_BY_GROUP_JOB,
       JOBS_PRINT_WAITING,
       BATCH_RUNNING,
       BATCH_WAITING_TO_RUN,
       BATCH_ENDING,
       BATCH_MESSAGE_WAIT,
       BATCH_HELD_WHILE_RUNNING,
       BATCH_HELD_ON_JOBQ,
       BATCH_ON_HELD_JOBQ,
       BATCH_ON_UNASSIGNED_JOBQ,
       BATCH_PRINT_WAITING,
       ELAPSED_TIME,
       ELAPSED_CPU_USED,
       ELAPSED_CPU_SHARED,
       ELAPSED_CPU_UNCAPPED_CAPACITY,
       CONFIGURED_CPUS,
       CPU_SHARING_ATTRIBUTE,
       CURRENT_CPU_CAPACITY,
       MAIN_STORAGE_SIZE,
       SYSTEM_ASP_STORAGE,
       TOTAL_AUXILIARY_STORAGE,
       SYSTEM_ASP_USED,
       CURRENT_TEMPORARY_STORAGE,
       MAXIMUM_TEMPORARY_STORAGE_USED,
       PERMANENT_ADDRESS_RATE,
       TEMPORARY_ADDRESS_RATE,
       TEMPORARY_256MB_SEGMENTS,
       TEMPORARY_4GB_SEGMENTS,
       PERMANENT_256MB_SEGMENTS,
       PERMANENT_4GB_SEGMENTS,
       TEMPORARY_JOB_STRUCTURES_AVAILABLE,
       PERMANENT_JOB_STRUCTURES_AVAILABLE,
       TOTAL_JOB_TABLE_ENTRIES,
       AVAILABLE_JOB_TABLE_ENTRIES,
       IN_USE_JOB_TABLE_ENTRIES,
       ACTIVE_JOB_TABLE_ENTRIES,
       JOBQ_JOB_TABLE_ENTRIES,
       OUTQ_JOB_TABLE_ENTRIES,
       JOBLOG_PENDING_JOB_TABLE_ENTRIES,
       HOST_NAME,
       PARTITION_ID,
       NUMBER_OF_PARTITIONS,
       ACTIVE_THREADS_IN_SYSTEM,
       RESTRICTED_STATE,
       PARTITION_NAME,
       PARTITION_GROUP_ID,
       SHARED_PROCESSOR_POOL_ID,
       DEFINED_MEMORY,
       MINIMUM_MEMORY,
       MAXIMUM_MEMORY,
       MEMORY_INCREMENT,
       DEDICATED_PROCESSORS,
       PHYSICAL_PROCESSORS,
       PHYSICAL_PROCESSORS_SHARED_POOL,
       MAXIMUM_PHYSICAL_PROCESSORS,
       DEFINED_VIRTUAL_PROCESSORS,
       VIRTUAL_PROCESSORS,
       MINIMUM_VIRTUAL_PROCESSORS,
       MAXIMUM_VIRTUAL_PROCESSORS,
       DEFINED_PROCESSING_CAPACITY,
       PROCESSING_CAPACITY,
       UNALLOCATED_PROCESSING_CAPACITY,
       MINIMUM_REQUIRED_PROCESSING_CAPACITY,
       MAXIMUM_LICENSED_PROCESSING_CAPACITY,
       MINIMUM_PROCESSING_CAPACITY,
       MAXIMUM_PROCESSING_CAPACITY,
       PROCESSING_CAPACITY_INCREMENT,
       DEFINED_INTERACTIVE_CAPACITY,
       INTERACTIVE_CAPACITY,
       INTERACTIVE_THRESHOLD,
       UNALLOCATED_INTERACTIVE_CAPACITY,
       MINIMUM_INTERACTIVE_CAPACITY,
       MAXIMUM_INTERACTIVE_CAPACITY,
       DEFINED_VARIABLE_CAPACITY_WEIGHT,
       VARIABLE_CAPACITY_WEIGHT,
       UNALLOCATED_VARIABLE_CAPACITY_WEIGHT,
       HARDWARE_MULTITHREADING,
       BOUND_HARDWARE_THREADS,
       THREADS_PER_PROCESSOR,
       DISPATCH_LATENCY,
       DISPATCH_WHEEL_ROTATION_TIME,
       TOTAL_CPU_TIME,
       INTERACTIVE_CPU_TIME,
       INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD,
       UNUSED_CPU_TIME_SHARED_POOL,
       MACHINE_TYPE,
       MACHINE_MODEL,
       SERIAL_NUMBER,
       MACHINE_SERIAL_NUMBER,
       ATTENTION_LIGHT,
       IPL_MODE,
       IPL_TYPE,
       JOURNAL_RECOVERY_COUNT,
       JOURNAL_CACHE_WAIT_TIME,
       JOB_SCHEDULE_STATUS,
       ACCESS_PATH_TARGET_RECOVERY_TIME,
       SMAPP_INCLUDE_ACCESS_PATHS,
       ACCESS_PATH_ESTIMATED_RECOVERY_TIME,
       ACCESS_PATH_ESTIMATED_INELIGIBLE_RECOVERY_TIME,
       SMAPP_DISK_STORAGE_USED,
       POWER_ENTERPRISE_POOL_PROCESSORS
    FROM qsys2.SYSTEM_STATUS_INFO
;
SQL

There are several fields to consider if we need to use this during our output processing, but rest assured, we have AI and computers to handle the heavy lifting for us. 

Let’s do an example of a NAME/VALUE table with fields for an UNPIVOT SQL example :

SQL

-- example of the "NAME/VALUE"
select SystemStatusValueName, SystemStatusValueName
  from qsys2.SYSTEM_STATUS_INFO t,
       lateral (values 
                       ('TOTAL_JOBS_IN_SYSTEM', t.TOTAL_JOBS_IN_SYSTEM),
                       ('MAXIMUM_JOBS_IN_SYSTEM', t.MAXIMUM_JOBS_IN_SYSTEM),
                       ('ACTIVE_JOBS_IN_SYSTEM', t.ACTIVE_JOBS_IN_SYSTEM)
                ) as q (SystemStatusValueName, SystemStatusValueName);

SQL

But, I do need more to expand on this, so I use a bit of ChatGPT/AI Magic with this prompt:

“Take the Original Query that I paste HERE <PASTE THE ORIGINAL FULL SELECT COLUMN QUERY HERE> and Modify it the same as this following query example
<– example of the “NAME/VALUE”
select SystemStatusValueName, SystemStatusValueName
  from qsys2.SYSTEM_STATUS_INFO t,
       lateral (values (‘TOTAL_JOBS_IN_SYSTEM’, t.TOTAL_JOBS_IN_SYSTEM),
                       (‘MAXIMUM_JOBS_IN_SYSTEM’, t.MAXIMUM_JOBS_IN_SYSTEM),
                       (‘ACTIVE_JOBS_IN_SYSTEM’, t.ACTIVE_JOBS_IN_SYSTEM)
                ) as q (SystemStatusValueName, SystemStatusValueName);
>

And it magically makes all of those columns appear for me as if I did it by hand like so:

SQL

--use then some AI hotsauce to complete the rest. 
SELECT SystemStatusValueName, SystemStatusValue
FROM qsys2.SYSTEM_STATUS_INFO t,
     LATERAL (VALUES 
        ('TOTAL_JOBS_IN_SYSTEM', t.TOTAL_JOBS_IN_SYSTEM),
        ('MAXIMUM_JOBS_IN_SYSTEM', t.MAXIMUM_JOBS_IN_SYSTEM),
        ('ACTIVE_JOBS_IN_SYSTEM', t.ACTIVE_JOBS_IN_SYSTEM),
        ('INTERACTIVE_JOBS_IN_SYSTEM', t.INTERACTIVE_JOBS_IN_SYSTEM),
        ('JOBS_SIGNED_ON', t.JOBS_SIGNED_ON),
        ('JOBS_DISCONNECTED', t.JOBS_DISCONNECTED),
        ('JOBS_SUSPENDED_BY_SYSREQ', t.JOBS_SUSPENDED_BY_SYSREQ),
        ('JOBS_SUSPENDED_BY_GROUP_JOB', t.JOBS_SUSPENDED_BY_GROUP_JOB),
        ('JOBS_PRINT_WAITING', t.JOBS_PRINT_WAITING),
        ('BATCH_RUNNING', t.BATCH_RUNNING),
        ('BATCH_WAITING_TO_RUN', t.BATCH_WAITING_TO_RUN),
        ('BATCH_ENDING', t.BATCH_ENDING),
        ('BATCH_MESSAGE_WAIT', t.BATCH_MESSAGE_WAIT),
        ('BATCH_HELD_WHILE_RUNNING', t.BATCH_HELD_WHILE_RUNNING),
        ('BATCH_HELD_ON_JOBQ', t.BATCH_HELD_ON_JOBQ),
        ('BATCH_ON_HELD_JOBQ', t.BATCH_ON_HELD_JOBQ),
        ('BATCH_ON_UNASSIGNED_JOBQ', t.BATCH_ON_UNASSIGNED_JOBQ),
        ('BATCH_PRINT_WAITING', t.BATCH_PRINT_WAITING),
        ('ELAPSED_TIME', t.ELAPSED_TIME),
        ('ELAPSED_CPU_USED', t.ELAPSED_CPU_USED),
        ('ELAPSED_CPU_SHARED', t.ELAPSED_CPU_SHARED),
        ('ELAPSED_CPU_UNCAPPED_CAPACITY', t.ELAPSED_CPU_UNCAPPED_CAPACITY),
        ('CONFIGURED_CPUS', t.CONFIGURED_CPUS),
        ('CPU_SHARING_ATTRIBUTE', t.CPU_SHARING_ATTRIBUTE),
        ('CURRENT_CPU_CAPACITY', t.CURRENT_CPU_CAPACITY),
        ('MAIN_STORAGE_SIZE', t.MAIN_STORAGE_SIZE),
        ('SYSTEM_ASP_STORAGE', t.SYSTEM_ASP_STORAGE),
        ('TOTAL_AUXILIARY_STORAGE', t.TOTAL_AUXILIARY_STORAGE),
        ('SYSTEM_ASP_USED', t.SYSTEM_ASP_USED),
        ('CURRENT_TEMPORARY_STORAGE', t.CURRENT_TEMPORARY_STORAGE),
        ('MAXIMUM_TEMPORARY_STORAGE_USED', t.MAXIMUM_TEMPORARY_STORAGE_USED),
        ('PERMANENT_ADDRESS_RATE', t.PERMANENT_ADDRESS_RATE),
        ('TEMPORARY_ADDRESS_RATE', t.TEMPORARY_ADDRESS_RATE),
        ('TEMPORARY_256MB_SEGMENTS', t.TEMPORARY_256MB_SEGMENTS),
        ('TEMPORARY_4GB_SEGMENTS', t.TEMPORARY_4GB_SEGMENTS),
        ('PERMANENT_256MB_SEGMENTS', t.PERMANENT_256MB_SEGMENTS),
        ('PERMANENT_4GB_SEGMENTS', t.PERMANENT_4GB_SEGMENTS),
        ('TEMPORARY_JOB_STRUCTURES_AVAILABLE', t.TEMPORARY_JOB_STRUCTURES_AVAILABLE),
        ('PERMANENT_JOB_STRUCTURES_AVAILABLE', t.PERMANENT_JOB_STRUCTURES_AVAILABLE),
        ('TOTAL_JOB_TABLE_ENTRIES', t.TOTAL_JOB_TABLE_ENTRIES),
        ('AVAILABLE_JOB_TABLE_ENTRIES', t.AVAILABLE_JOB_TABLE_ENTRIES),
        ('IN_USE_JOB_TABLE_ENTRIES', t.IN_USE_JOB_TABLE_ENTRIES),
        ('ACTIVE_JOB_TABLE_ENTRIES', t.ACTIVE_JOB_TABLE_ENTRIES),
        ('JOBQ_JOB_TABLE_ENTRIES', t.JOBQ_JOB_TABLE_ENTRIES),
        ('OUTQ_JOB_TABLE_ENTRIES', t.OUTQ_JOB_TABLE_ENTRIES),
        ('JOBLOG_PENDING_JOB_TABLE_ENTRIES', t.JOBLOG_PENDING_JOB_TABLE_ENTRIES),
        ('HOST_NAME', t.HOST_NAME),
        ('PARTITION_ID', t.PARTITION_ID),
        ('NUMBER_OF_PARTITIONS', t.NUMBER_OF_PARTITIONS),
        ('ACTIVE_THREADS_IN_SYSTEM', t.ACTIVE_THREADS_IN_SYSTEM),
        ('RESTRICTED_STATE', t.RESTRICTED_STATE),
        ('PARTITION_NAME', t.PARTITION_NAME),
        ('PARTITION_GROUP_ID', t.PARTITION_GROUP_ID),
        ('SHARED_PROCESSOR_POOL_ID', t.SHARED_PROCESSOR_POOL_ID),
        ('DEFINED_MEMORY', t.DEFINED_MEMORY),
        ('MINIMUM_MEMORY', t.MINIMUM_MEMORY),
        ('MAXIMUM_MEMORY', t.MAXIMUM_MEMORY),
        ('MEMORY_INCREMENT', t.MEMORY_INCREMENT),
        ('DEDICATED_PROCESSORS', t.DEDICATED_PROCESSORS),
        ('PHYSICAL_PROCESSORS', t.PHYSICAL_PROCESSORS),
        ('PHYSICAL_PROCESSORS_SHARED_POOL', t.PHYSICAL_PROCESSORS_SHARED_POOL),
        ('MAXIMUM_PHYSICAL_PROCESSORS', t.MAXIMUM_PHYSICAL_PROCESSORS),
        ('DEFINED_VIRTUAL_PROCESSORS', t.DEFINED_VIRTUAL_PROCESSORS),
        ('VIRTUAL_PROCESSORS', t.VIRTUAL_PROCESSORS),
        ('MINIMUM_VIRTUAL_PROCESSORS', t.MINIMUM_VIRTUAL_PROCESSORS),
        ('MAXIMUM_VIRTUAL_PROCESSORS', t.MAXIMUM_VIRTUAL_PROCESSORS),
        ('DEFINED_PROCESSING_CAPACITY', t.DEFINED_PROCESSING_CAPACITY),
        ('PROCESSING_CAPACITY', t.PROCESSING_CAPACITY),
        ('UNALLOCATED_PROCESSING_CAPACITY', t.UNALLOCATED_PROCESSING_CAPACITY),
        ('MINIMUM_REQUIRED_PROCESSING_CAPACITY', t.MINIMUM_REQUIRED_PROCESSING_CAPACITY),
        ('MAXIMUM_LICENSED_PROCESSING_CAPACITY', t.MAXIMUM_LICENSED_PROCESSING_CAPACITY),
        ('MINIMUM_PROCESSING_CAPACITY', t.MINIMUM_PROCESSING_CAPACITY),
        ('MAXIMUM_PROCESSING_CAPACITY', t.MAXIMUM_PROCESSING_CAPACITY),
        ('PROCESSING_CAPACITY_INCREMENT', t.PROCESSING_CAPACITY_INCREMENT),
        ('DEFINED_INTERACTIVE_CAPACITY', t.DEFINED_INTERACTIVE_CAPACITY),
        ('INTERACTIVE_CAPACITY', t.INTERACTIVE_CAPACITY),
        ('INTERACTIVE_THRESHOLD', t.INTERACTIVE_THRESHOLD),
        ('UNALLOCATED_INTERACTIVE_CAPACITY', t.UNALLOCATED_INTERACTIVE_CAPACITY),
        ('MINIMUM_INTERACTIVE_CAPACITY', t.MINIMUM_INTERACTIVE_CAPACITY),
        ('MAXIMUM_INTERACTIVE_CAPACITY', t.MAXIMUM_INTERACTIVE_CAPACITY),
        ('DEFINED_VARIABLE_CAPACITY_WEIGHT', t.DEFINED_VARIABLE_CAPACITY_WEIGHT),
        ('VARIABLE_CAPACITY_WEIGHT', t.VARIABLE_CAPACITY_WEIGHT),
        ('UNALLOCATED_VARIABLE_CAPACITY_WEIGHT', t.UNALLOCATED_VARIABLE_CAPACITY_WEIGHT),
        ('HARDWARE_MULTITHREADING', t.HARDWARE_MULTITHREADING),
        ('BOUND_HARDWARE_THREADS', t.BOUND_HARDWARE_THREADS),
        ('THREADS_PER_PROCESSOR', t.THREADS_PER_PROCESSOR),
        ('DISPATCH_LATENCY', t.DISPATCH_LATENCY),
        ('DISPATCH_WHEEL_ROTATION_TIME', t.DISPATCH_WHEEL_ROTATION_TIME),
        ('TOTAL_CPU_TIME', t.TOTAL_CPU_TIME),
        ('INTERACTIVE_CPU_TIME', t.INTERACTIVE_CPU_TIME),
        ('INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD', t.INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD),
        ('UNUSED_CPU_TIME_SHARED_POOL', t.UNUSED_CPU_TIME_SHARED_POOL),
        ('MACHINE_TYPE', t.MACHINE_TYPE),
        ('MACHINE_MODEL', t.MACHINE_MODEL),
        ('SERIAL_NUMBER', t.SERIAL_NUMBER),
        ('MACHINE_SERIAL_NUMBER', t.MACHINE_SERIAL_NUMBER),
        ('ATTENTION_LIGHT', t.ATTENTION_LIGHT),
        ('IPL_MODE', t.IPL_MODE),
        ('IPL_TYPE', t.IPL_TYPE),
        ('JOURNAL_RECOVERY_COUNT', t.JOURNAL_RECOVERY_COUNT),
        ('JOURNAL_CACHE_WAIT_TIME', t.JOURNAL_CACHE_WAIT_TIME),
        ('JOB_SCHEDULE_STATUS', t.JOB_SCHEDULE_STATUS),
        ('ACCESS_PATH_TARGET_RECOVERY_TIME', t.ACCESS_PATH_TARGET_RECOVERY_TIME),
        ('SMAPP_INCLUDE_ACCESS_PATHS', t.SMAPP_INCLUDE_ACCESS_PATHS),
        ('ACCESS_PATH_ESTIMATED_RECOVERY_TIME', t.ACCESS_PATH_ESTIMATED_RECOVERY_TIME),
        ('ACCESS_PATH_ESTIMATED_INELIGIBLE_RECOVERY_TIME', t.ACCESS_PATH_ESTIMATED_INELIGIBLE_RECOVERY_TIME),
        ('SMAPP_DISK_STORAGE_USED', t.SMAPP_DISK_STORAGE_USED),
        ('POWER_ENTERPRISE_POOL_PROCESSORS', t.POWER_ENTERPRISE_POOL_PROCESSORS)
     ) AS q(SystemStatusValueName, SystemStatusValue);

SQL

Now that I have this, let’s see the output by running it.  

Please note that some of the values are non-readable and need some adjusting.

The reason here is that the first value SQL sees most in the result set as a number will then be used as a number in the result set and here on planet earth, letters cannot be cast to numbers.

Now let me do some further AI Magic prompt:

“For each of the values inside of this query <PASTE THE FULL QUERY THAT AI GENERATED PREVIOUSLY> and alter each of those values with the following pattern  
 (‘INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD’, t.INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD),


Becomes

(‘INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD’, IFNULL(CHAR(t.INTERACTIVE_CPU_TIME_ABOVE_THRESHOLD), ”)),
And so forth.”

What this will do is cast each value to a CHAR and if it’s a NULL replace that with a BLANK value.

Check the resulting output carefully, AI is quite good at helping out but could make some mistakes.  

Now we are getting somewhere, notice the previous values are the way I would like it as a CHAR and with NULLS replaced as blanks (don’t worry, the magic will show best at the end result):

sql

Great! The next part becomes more effortless; I create a view of this initial query now like so:

SQL

CREATE VIEW QGPL.SYSTEMSTATUSNAMEVALUE AS (
<PASTE THE ALTERED AI WITH CHAR AND NULL QUERY HERE> 
);
SQL

This just makes things easier to work in the next step,

For the sake of demo and explanation, I am creating a quick & dirty table here with some random data with this SQL:

SQL

-- for sake of demo and my sanity at this night, quick and dirty for great demo coverage. 
CREATE TABLE QGPL.SYSTEMSTATSTABLEFORDEMO AS ( 
    select SYSTEMSTATUSVALUENAME,SYSTEMSTATUSVALUE, CURRENT TIMESTAMP AS TIMESTAMPVALUE from QGPL.SYSTEMSTATUSNAMEVALUE
) WITH DATA  ;

--- here I can run it again with a new value and some "randomness perhaps" thrown in for some values to test with... 
insert into QGPL.SYSTEMSTATSTABLEFORDEMO (
    select SYSTEMSTATUSVALUENAME,TRIM(SYSTEMSTATUSVALUE)||CHAR(int(rand()*10)), current timestamp  from QGPL.SYSTEMSTATUSNAMEVALUE
    WHERE SYSTEMSTATUSVALUENAME IN ('TOTAL_JOBS_IN_SYSTEM','MAXIMUM_JOBS_IN_SYSTEM','ACTIVE_JOBS_IN_SYSTEM','CONFIGURED_CPUS')
);

SQL

What this result table gives is a way for me to collate all values from most QSYS tables in a uniform manner to analyse later over a period of time.

Usage Example:

For example, if I am interested in the TOTAL_JOBS_IN_SYSTEM in 30-minute increments, I can pivot it over the value column like this:

SQL

---Lets to compare them side by side now------ perhaps to see the time interval in 30 mins of what was captured as values
WITH DataTable as (
    select * from QGPL.SYSTEMSTATSTABLEFORDEMO 
) 
select SYSTEMSTATUSVALUENAME,
    MAX(CASE WHEN MINUTE(TIMESTAMPVALUE) BETWEEN 1 AND 30 THEN SYSTEMSTATUSVALUE ELSE '' END ) AS STATUSVALUE0TO30MINS,
    MAX(CASE WHEN MINUTE(TIMESTAMPVALUE) BETWEEN 30 AND 59 THEN SYSTEMSTATUSVALUE ELSE '' END ) AS STATUSVALUE30TO59MINS
from datatable
where SYSTEMSTATUSVALUENAME= 'TOTAL_JOBS_IN_SYSTEM' 
group by SYSTEMSTATUSVALUENAME
;

SQL

A nice result over the PIVOT values of what I have specified:

Another example to show what is possible if one stages the output of these queries in a uniform casted manner:

Conclusion

This demonstrates an effective method for using SQL to collate different types of values and present the status values in a digestible and functional way.

This approach also makes it easier to integrate other tables into a single end table for tracking history.

How useful was this post?

Click on a star to rate it!

Average rating 4.9 / 5. Vote count: 9

No votes so far! Be the first to rate this post.


Comments

4 responses to “Stretch Imagination with SQL Part1”

  1. Great article! The SQL method shared is practical and easy to apply. Thanks! Looking forward to the next article.

    1. Andy Youens avatar
      Andy Youens

      Thank you for taking the time to comment on Marius’s article. We agree with you!

    1. Andy Youens avatar
      Andy Youens

      Thanks for your PowerWire support as always Jesse!

Leave a Reply

Your email address will not be published. Required fields are marked *