1

I have a table that looks like this:


| Scenario| Date   | System | Result |
| ------- | ------ | ------ | ------ |
| Proj1   | 07-01  | A      | PASS   |
| Proj1   | 07-01  | B      | PASS   |
| Proj1   | 07-01  | C      | PASS   |
| Proj1   | 07-01  | D      | PASS   |
| Proj1   | 07-02  | A      | FAIL   |
| Proj1   | 07-02  | B      | FAIL   |
| Proj1   | 07-02  | C      | FAIL   |
| Proj1   | 07-02  | D      | FAIL   |
| Proj2   | 07-01  | E      | PASS   |
| Proj2   | 07-01  | F      | FAIL   |
| Proj2   | 07-02  | E      | PASS   |
| Proj2   | 07-02  | F      | PASS   |

I rearranged it to this:

| Scenario| Date | System1 | System2 | System3 | System4| Overall|
| ------- | ---- | ------- | ------- | ------- | -------|--------|
| Proj1   | 07-01| A-PASS  | B-PASS  | C-PASS  | D-PASS |PASS    |
| Proj1   | 07-02| A-FAIL  | B-FAIL  | C-FAIL  | D-FAIL |FAIL    |
| Proj2   | 07-01| E-PASS  | F-FAIL  |         |        |FAIL    |
| Proj2   | 07-02| E-PASS  | F-PASS  |         |        |PASS    |

Right now, the order of the systems is alphabetical but I created a mapping table in which it orders the priority of the systems

|Scenario|System | Priority|
|------- |-------| --------|
|Proj1   |A      | 2       |
|Proj1   |B      | 3       |
|Proj1   |C      | 1       |
|Proj1   |D      | 4       |
|Proj2   |E      | 1       |
|Proj2   |F      | 2       |

Is there a way to adjust the order such that it reflects the priority and is as such:

| Scenario| Date | System1 | System2 | System3 | System4| Overall|
| ------- | ---- | ------- | ------- | ------- | -------|--------|
| Proj1   | 07-01| C-PASS  | A-PASS  | B-PASS  | D-PASS |PASS    |
| Proj1   | 07-02| C-FAIL  | A-FAIL  | B-FAIL  | D-FAIL |FAIL    |
| Proj2   | 07-01| E-PASS  | F-FAIL  |         |        |FAIL    |
| Proj2   | 07-02| E-PASS  | F-PASS  |         |        |PASS    |

  • Instead of producing 4 columns, maybe you could produce a single one with comma-separated values. – The Impaler Aug 02 '22 at 15:27
  • I considered that, but I from a aesthetic perspective, I think it looked clearer separating the columns. Thanks for the suggestion! – wadeland1738 Aug 02 '22 at 15:34

1 Answers1

1

You may find the count of all systems for a specific (Date,Scenario) by using Count(*) over (Partition By Scenario,Date), and the count of only passed systems for that (Date,Scenario) by using Aggregate Filter as the following, count(*) filter (where Result='PASS') over (Partition By Scenario,Date).

Then compare the two counts, if they are equal then set the overall result as PASS.

Consider the following:

Create Or Replace Function pvt()
    RETURNS void
    LANGUAGE 'plpgsql'
As $body$
declare
    sqlColumn varchar;
    qr varchar;
    columnlist varchar;
Begin
sqlColumn= 'select distinct D.sys_cat from (select Row_Number() Over (Partition By Scenario,Date Order By System) as sys_cat From run) D order by D.sys_cat;';
qr='prepare pvtstmt AS Select D.Scenario,D.Date,';

For columnlist In EXECUTE sqlColumn  
   Loop
      qr=qr || 'Max(Case When sys_cat=' || columnlist || ' Then (System || ''_'' || Result) Else '''' End) As System' ||  columnlist ||  ' , ';
   END LOOP;
   
   --qr=substr(qr, 0, length(qr) - 1);
   qr=qr|| 'case when D.tc= D.pc then ''PASS'' else ''FAIL'' end as overall ';
   qr=qr || 'From (select *, Count(*) over (Partition By Scenario,Date) tc,'||
   ' count(*) filter (where Result=''PASS'') over (Partition By Scenario,Date) pc,'||
   '  Row_Number() Over (Partition By Scenario,Date Order By System) as sys_cat From run) D Where D.Scenario =' 
   || '''Proj1'' Group By D.Scenario,D.Date,overall Order By D.Scenario,D.Date';
   
Deallocate All;
EXECUTE qr;
End;
$body$

See a demo from db<>fiddle.

For the second required output, you may use the following function:

Create Or Replace Function pvt(qr_selector int, Scenario_selector varchar default 'all')
    RETURNS void
    LANGUAGE plpgsql AS
$body$
declare
    sqlColumn varchar;
    qr varchar; qr2 varchar;
    columnlist varchar;
Begin
  sqlColumn= 'select distinct D.sys_cat from (select Row_Number() Over (Partition By Scenario,Date Order By System) as sys_cat From run) D order by D.sys_cat;';
  qr='Select D.Scenario,D.Date,';

  For columnlist In EXECUTE sqlColumn  
   Loop
      qr=qr || 'Max(Case When sys_cat=' || columnlist || ' Then (System || ''_'' || Result) Else '''' End) As System' ||  columnlist ||  ' , ';
   END LOOP;
   
   --qr=substr(qr, 0, length(qr) - 1);
  qr=qr|| 'case when D.tc= D.pc then ''PASS'' else ''FAIL'' end as overall ';
  qr=qr || 'From (select *, Count(*) over (Partition By Scenario,Date) tc,'||
  ' count(*) filter (where Result=''PASS'') over (Partition By Scenario,Date) pc,'||
  '  Row_Number() Over (Partition By Scenario,Date Order By System) as sys_cat From run) D ';
   
  if Scenario_selector='all' then
    qr=qr || ' Group By D.Scenario,D.Date,overall Order By D.Scenario,D.Date';
  else
    qr=qr || 'Where D.Scenario =''' || Scenario_selector || ''' Group By D.Scenario,D.Date,overall Order By D.Scenario,D.Date';
  end if;
   
  qr2='with cte as (' || qr || ') Select date, count(*) filter (where overall=''PASS'') as Num_Of_Passes,' ||
  'count(*) filter (where overall=''FAIL'') as Num_Of_Fails ' ||
  'from cte group by date;';
   
  Deallocate All;

  if qr_selector = 1 then
   EXECUTE 'prepare pvtstmt AS ' || qr;
  else
   EXECUTE 'prepare pvtstmt AS ' || qr2;
  end if;
End;
$body$

The first parameter in the function qr_selector lets you to choose what query to execute, 1 for the first output, 2 for the second output. The second parameter Scenario_selector lets you to filter the Scenario values, where the default value is 'all'.

i.e. to select the first output result for all Scenario values use Select pvt(1);, and to select the second output result for Scenario = 'Proj1' use Select pvt(2,'Proj1');

See a demo from db<>fiddle.

ahmed
  • 9,071
  • 3
  • 9
  • 22
  • Wow - this is amazing. Thank you so much, this is all starting to make sense. Do you know if there is a way to query the results of this table? I was going to create a graph where I SUM when overall = "PASS" and overall = "FAIL" to show the progression of pass/fail on each day. – wadeland1738 Aug 02 '22 at 20:54
  • 1
    Can you edit the question and post a sample of the required output including that sums. – ahmed Aug 02 '22 at 21:03
  • Sure, just edited it! – wadeland1738 Aug 02 '22 at 21:19
  • 1
    The answer has been updated with the new requirement, also with more dynamic function. – ahmed Aug 02 '22 at 23:49
  • Wow, the idea of adding a second parameter was very cool. I was thinking of maybe creating a different function, this is much more concise. Also, I have edited the question and was wondering if you knew if there was a way to adjust the order of the systems? I was thinking of creating some parameter within the loop but was not sure if that is possible? – wadeland1738 Aug 03 '22 at 17:14
  • please let me know if what I said makes sense, I can clarify. thank you so much for your help - I am learning a lot. – wadeland1738 Aug 03 '22 at 18:14
  • Yes that's simple, instead of sorting according to `System`, sort according to `Priority` in the `sqlColumn` variable. check this https://dbfiddle.uk/?rdbms=postgres_14&fiddle=4727be5585927cebdbbb58a2684e6790 – ahmed Aug 03 '22 at 20:08
  • yeah that's what I was thinking but the problem I was having was that the Priority is in a separate table, not the run table. – wadeland1738 Aug 03 '22 at 20:11
  • You can join that table with `run` on `Scenario` and `Date` to get the priority from it. – ahmed Aug 03 '22 at 20:13
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247014/discussion-between-wadeland1738-and-ahmed). – wadeland1738 Aug 03 '22 at 21:32