2

I am trying to incorporate the null values within the returned lists, such that:

batch_id   |test_name   |test_value
-----------------------------------
10         | pH         | 4.7
10         | Temp       | 154
11         | pH         | 4.8
11         | Temp       | 152
12         | pH         | 4.5
13         | Temp       | 155
14         | pH         | 4.9
14         | Temp       | 152
15         | Temp       | 149
16         | pH         | 4.7
16         | Temp       | 150

would return:

batch_id   | pH         |Temp 
---------------------------------------
10         |  4.7       |   154
11         |  4.8       |   152
12         |  4.5       |   <null>
13         |  <null>    |   155
14         |  4.9       |   152
15         |  <null>    |   149
16         |  4.7       |   150

However, it currently returns this:

batch_id   | pH         |Temp 
---------------------------------------
10         |  4.7       |   154
11         |  4.8       |   152
12         |  4.5       |   <null>
13         |  155       |   <null>
14         |  4.9       |   152
15         |  149       |   <null>
16         |  4.7       |   150

This is an extension of a prior question - Can the categories in the postgres tablefunc crosstab() function be integers? - which led to this current query:

SELECT *
 FROM crosstab('SELECT lab_tests_results.batch_id, lab_tests.test_name, lab_tests_results.test_result::FLOAT
                FROM lab_tests_results, lab_tests
                WHERE lab_tests.id=lab_tests_results.lab_test AND (lab_tests.test_name LIKE ''Test Name 1'' OR lab_tests.test_name LIKE ''Test Name 2'')
                ORDER BY 1,2'
            )   AS final_result(batch_id VARCHAR, test_name_1 FLOAT, test_name_2 FLOAT);

I also know that I am not the first to ask this question generally, but I have yet to find a solution that works for these circumstances. For example, this one - How to include null values in `tablefunc` query in postgresql? - assumes the same Batch IDs each time. I do not want to specify the Batch IDs, but rather all that are available.

This leads into the other set of solutions I've found out there, which address a null list result from specified categories. Since I'm just taking what's already there, however, this isn't an issue. It's the null individual values causing the problem and resulting in a pivot table with values shifted to the left.

Any suggestions are much appreciated!

Edit: With Klin's help, got it sorted out. Something to note is that the VALUES section must match the actual lab_tests.test_name values you're after, such that:

SELECT *
    FROM crosstab(
            $$
                SELECT lab_tests_results.batch_id, lab_tests.test_name,  lab_tests_results.test_result::FLOAT
            FROM lab_tests_results, lab_tests
            WHERE lab_tests.id = lab_tests_results.lab_test
                AND (
                lab_tests_results.lab_test = 1 
                OR lab_tests_results.lab_test = 2 
                OR lab_tests_results.lab_test = 3 
                OR lab_tests_results.lab_test = 4 
                OR lab_tests_results.lab_test = 5 
                OR lab_tests_results.lab_test = 50 )
            ORDER BY 1 DESC, 2
        $$,
        $$
                VALUES('Mash pH'),
                    ('Sparge pH'),
                    ('Final Lauter pH'),
                    ('Wort pH'),
                    ('Wort FAN'),
                    ('Original Gravity'),
                    ('Mash Temperature')
        $$
        )   AS final_result(batch_id VARCHAR,
                            ph_mash FLOAT, 
                            ph_sparge FLOAT, 
                            ph_final_lauter FLOAT, 
                            ph_wort FLOAT, 
                            FAN_wort FLOAT, 
                            original_gravity FLOAT, 
                            mash_temperature FLOAT)

Thanks for the help!

user1644030
  • 251
  • 3
  • 10

1 Answers1

2

Use the second form of the function:

crosstab(text source_sql, text category_sql) - Produces a “pivot table” with the value columns specified by a second query.

E.g.:

SELECT *
FROM crosstab(
    $$
        SELECT lab_tests_results.batch_id, lab_tests.test_name, lab_tests_results.test_result::FLOAT
        FROM lab_tests_results, lab_tests
        WHERE lab_tests.id=lab_tests_results.lab_test 
        AND (
            lab_tests.test_name LIKE 'Test Name 1' 
            OR lab_tests.test_name LIKE 'Test Name 2')
        ORDER BY 1,2
    $$,
    $$ 
        VALUES('pH'), ('Temp') 
    $$
) AS final_result(batch_id VARCHAR, "pH" FLOAT, "Temp" FLOAT);
klin
  • 112,967
  • 15
  • 204
  • 232