Crosstab function does not exist

I've seen in this github issue and this forum post that some users have successfully managed to use postgres' crosstab function, however, when I try to use it, I see the following error:

ERROR: function crosstab(unknown, unknown) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 14

SELECT * FROM crosstab('
    SELECT
    	EXTRACT(YEAR FROM m.created_at) || ''-'' || EXTRACT(MONTH FROM m.created_at) month_id,
    	o.display_name org_name,
    	count(DISTINCT m.user_id) mau
    FROM mood m
    JOIN "user" u ON m.user_id  = u.id
    JOIN organization o ON u.organization_id = o.id
    JOIN (
    	SELECT
    		sub.org_id
    	FROM (
    		SELECT
    			EXTRACT(YEAR FROM m.created_at) || ''-'' || EXTRACT(MONTH FROM m.created_at) month_id,
    			o.id org_id,
    			count(DISTINCT m.user_id) mau
    		FROM mood m
    		JOIN "user" u ON m.user_id  = u.id
    		JOIN organization o ON u.organization_id = o.id
    		WHERE o.slack_id NOT ILIKE ''T01AU0YAGJF''
    		GROUP BY
    			EXTRACT(YEAR FROM m.created_at),
    			EXTRACT(MONTH FROM m.created_at),
    			o.id
    		ORDER BY
    			EXTRACT(YEAR FROM m.created_at),
    			EXTRACT(MONTH FROM m.created_at)
    	) sub
    	GROUP BY sub.org_id
    	HAVING max(sub.mau) > 2
    ) org_ids ON org_ids.org_id = o.id
    GROUP BY
    	EXTRACT(YEAR FROM m.created_at),
    	EXTRACT(MONTH FROM m.created_at),
    	o.id
    ORDER BY
    	EXTRACT(YEAR FROM m.created_at),
    	EXTRACT(MONTH FROM m.created_at)
    ',
    '
    SELECT
    	sub.org_name
    FROM (
    	SELECT
    		EXTRACT(YEAR FROM m.created_at) || ''-'' || EXTRACT(MONTH FROM m.created_at) month_id,
    		o.display_name org_name,
    		count(DISTINCT m.user_id) mau
    	FROM mood m
    	JOIN "user" u ON m.user_id  = u.id
    	JOIN organization o ON u.organization_id = o.id
    	WHERE o.slack_id NOT ILIKE ''T01AU0YAGJF''
    	GROUP BY
    		EXTRACT(YEAR FROM m.created_at),
    		EXTRACT(MONTH FROM m.created_at),
    		o.id
    	ORDER BY
    		EXTRACT(YEAR FROM m.created_at),
    		EXTRACT(MONTH FROM m.created_at)
    ) sub
    GROUP BY sub.org_name
    HAVING max(sub.mau) > 2
    ORDER BY sub.org_name
    '
) AS ct (
	"month_id" TEXT,
	"our-client-name-1" bigint,
	"our-client-name-2" bigint,
	"our-client-name-3" bigint,
	"our-client-name-4" bigint
-- there are more clients here, with their actual names, which I have edited for privacy
)

I tried using $$ instead of single quotes around the crosstab arguments but that made no difference. I also tried explicitly casting them to text ::text but then I just got the same error but with crosstab(text, text) does not exist. I tried calling tablefunc.crosstab() but got schema "tablefunc" does not exist.

This is a screenshot of the same query working correctly in DBeaver, my database client.

The database I am using is hosted by supabase and I turned the tablefunc extension on this morning to allow me to use the crosstab function. It's working in my client, so I don't understand why it doesn't work in metabase.

Please could someone advise? I assume that there's some issue with my query that's the actual root cause but the error is pretty frustrating; I know the function is available on the database I'm querying. The only difference I can think of between my db client and metabase environments is that my local client is connected via a role that has full access and metabase is connected via one that is readonly, but I don't see how that would make a difference seeing as it's a select statement.

Hi @sauntimo
The error is coming from your database - not Metabase. Make sure it is installed and available the the user that Metabase uses for the connection.
https://stackoverflow.com/questions/3002499/postgresql-crosstab-query

1 Like

Thanks for this @flamber. I checked and it seems that enabling the tablefunc extension in supabase installs it to the extensions schema. My readonly user didn't have access to this schema. I was able to fix this by running

GRANT USAGE ON SCHEMA extensions TO readonly;

in psql. I then explicitly call extensions.crosstab() in the function.

Do you think it would be worth making the user feedback for failed queries a bit clearer, maybe something like "Metabase successfully ran the query but the connected database returned the following error" eg "it's not me, it's you..." :smile:

@sauntimo That is something we're working on - together a troubleshooting for the specific error, so it would show tips like I just provided, when we know about the error.
But we need to make sure we're not pointing fingers in the wrong direction either, since that could become a wild goose-chase.
As you can imagine, it's difficult to create something like that, while still preserving privacy, and having to support ~20 different database types.

PS - make sure you read https://github.com/metabase/metabase/issues/16949 if you want to combine filters in it. Slightly complicated.

Absolutely, I'm sure that will keep you busy! Thanks very much for your help today. I'd already come across that other issue in my googling around this, but I will bear that in mind :+1: