I have a table that I would like to pivot using cases in Redshift.
CREATE TABLE SurveyResponses (
id int,
question varchar(255),
answer varchar(255)
);
INSERT INTO SurveyResponses (id, question, answer) values (1, 'Dummy question 1', 'responseX');
INSERT INTO SurveyResponses (id, question, answer) values (2, 'Dummy question 1', 'responseY');
INSERT INTO SurveyResponses (id, question, answer) values (3, 'Dummy question 1', 'responseZ');
INSERT INTO SurveyResponses (id, question, answer) values (4, 'Dummy question 2', 'responseA');
INSERT INTO SurveyResponses (id, question, answer) values (5, 'Dummy question 2', 'responseB');
INSERT INTO SurveyResponses (id, question, answer) values (6, 'Dummy question 3', 'responseC');
I tried the following case approach which does not work. I get repeated rows.
Select id,
Case
When question = 'Dummy question 1' then answer Else '' End as question_1,
Case
When question = 'Dummy question 2' then answer Else '' End as question_2,
Case
When question = 'Dummy question 3' then answer Else '' End as question_3
FROM SurveyResponses;
ID
QUESTION_1
QUESTION_2
QUESTION_3
1
responseX
-
-
2
responseY
-
-
3
responseZ
-
-
4
-
responseA
-
5
-
responseB
-
6
-
-
responseC
1
responseX
-
-
2
responseY
-
-
3
responseZ
-
-
4
-
responseA
-
5
-
responseB
-
6
-
-
responseC
1
responseX
-
-
2
responseY
-
-
3
responseZ
-
-
4
-
responseA
-
5
-
responseB
-
6
-
-
responseC
Also, in my real table, I will have 5000+ questions. I would not like to write the case statement for every question. Also, I wanted my column name to be the question text.
Could someone help me in making it Dynamic?
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 29 days ago.
Improve this question
Given a text column in SQLite, how can I reverse its values?
For example, given this table:
CREATE TABLE "testwords" ("word" text);
INSERT INTO "testwords"("word") VALUES ('Hello'), ('world!'), ('foo bar baz');
which SELECT statements give 'olleH', '!dlrow', 'zab rab oof'?
You can do so with a recursive CTE (which is a bit involved for such a simple task):
-- Create and populate example table:
CREATE TABLE "testwords" ("word" text);
INSERT INTO "testwords"("word") VALUES ('Hello'), ('world!'), ('foo bar baz');
-- CTE to select the reversed characters from the "testwords" table:
WITH RECURSIVE "reverse" ("stringno", "string", "charno", "char") AS (
SELECT -- start at the last character:
_rowid_
, "word"
, length("word")
, substr("word", -1, 1)
FROM "testwords"
UNION ALL
SELECT -- recurse: move one letter to the left
"stringno"
, "string"
, "charno" - 1
, substr("string", "charno" - 1, 1)
FROM "reverse"
WHERE "charno" > 1 -- stop condition
)
SELECT
"string"
, group_concat("char", '') AS "reversed"
FROM "reverse"
GROUP BY "stringno";
The recursive CTE selects each character of each string (from right to left), and
stringno is a number suitable to group the characters of each string
string is the string that is being reversed
charno is the position of this character (and counts from length() down to 1)
char is the character itself
Finally, group_concat() is used to re-assemble the individual characters, giving the desired result:
| Hello | olleH |
| world! | !dlrow |
| foo bar baz | zab rab oof |
Been searching the forums on here but can't find anything that exactly replicates what I'm trying to do - I have split a string by delimiter and currently have an Excel file that has the following column names and some basic sample data:
Learnt 1 - Learnt 2 - Learnt 3 - Learnt 4
Books - (blank) - (blank) - (blank)
Online - Books - (blank) - (blank)
(blank) - Books - Bootcamp - (blank)
Bootcamp - (blank) - Books - (blank)
The four learnt columns are populated either by a method of learning (of which there's around 8 possibilities which apply to every column, or are blank, and more than one column can be non-blank at the same time in any given row. Very simply, I want to be able to count the total number of times each method appears in all the columns in PowerBI, so the expected results here would be Books 4, Online 1, Bootcamp 2. Any help would be greatly appreciated.
I have tried using the USERelationship function to link this to a separate table with all methods of learning listed out(Table 1), see query below but was having no luck:
CountinlearntocodeColumns =
CALCULATE (
COUNTROWS ( LearningMethodTable ),
USERELATIONSHIP ( Table1[Method], LearningMethodTable[Learnt 1] )
)
+ CALCULATE (
COUNTROWS ( LearningMethodTable ),
USERELATIONSHIP ( Table1[Method], LearningMethodTable[Learnt 2] )
)
+ CALCULATE (
COUNTROWS ( LearningMethodTable ),
USERELATIONSHIP ( Table1[Method], LearningMethodTable[Learnt 3] )
)
You make life unnecessarily difficult when working with pivoted tables in Power BI. Fix that first
In Power Query simply unpivot all columns and filter out blanks:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcsrPzy5WUNJRgqJYnWgl/7yczLxUkCCKLEgKWQzIKElOzC1QgEmiCCBrjo0FAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Learnt 1 " = _t, #"Learnt 2 " = _t, #"Learnt 3 " = _t, #"Learnt 4" = _t]),
#"Unpivoted Columns" = Table.UnpivotOtherColumns(
Source, {}, "Learnt", "Method"),
#"Filtered Rows" = Table.SelectRows(
#"Unpivoted Columns", each [Method] <> null and [Method] <> "")
in
#"Filtered Rows"
The result will look like this:
Now you can easily create your count in DAX
Count = Count('Table'[Method])
and pull it into a new result table:
Need help being new to "REGEXP_REPLACE".
When I do
SELECT REGEXP_REPLACE('7ELEVEN USA','[(\D^USA|^CANADA|^Canada)]','') "NAME" from dual
I get 7ELEVE and you can see that last character N is missing.
I want to replace first numbers from below & display 7-ELEVEN STORE.
20991 7-ELEVEN STORE
Any help is greatly appreciated.
Thanking in advance
I want to replace first numbers from below & display 7-ELEVEN STORE.
20991 7-ELEVEN STORE
Well, you don't even need regular expressions for that - the good, old SUBSTR + INSTR does the job just fine (that's RES2). If you want regexp, then this pattern: ^\d+ does it - it says:
^ anchor to the beginning of the string
\d+ take all digits there are (up to the first non-digit character, which is the space)
An example:
SQL> with test (col) as
2 (select '20991 7-ELEVEN STORE' from dual)
3 select
4 regexp_replace(col, '^\d+') res1,
5 substr(col, instr(col, ' ') + 1) res2
6 from test;
RES1 RES2
--------------- --------------
7-ELEVEN STORE 7-ELEVEN STORE
SQL>
[EDIT]
As of the first query you posted (I didn't understand it was the question): if you want to select the first "word" from that string, I wouldn't use REGEXP_REPLACE but (REGEXP_)SUBSTR:
SQL> with test (col) as
2 (select '7ELEVEN USA' from dual)
3 select regexp_substr(col, '\w+') res1,
4 substr(col, 1, instr(col, ' ') - 1) res2
5 from test;
RES1 RES2
------- -------
7ELEVEN 7ELEVEN
SQL>
This question already has answers here:
SQLite and custom order by
(3 answers)
Query Sqlite Database by specific/custom ordering?
(3 answers)
Closed 5 years ago.
I'm using SQLite and I'm providing a list of id values to retrieve. However, the order of those id values is important and I want to retrieve the records in the same order.
For example,
SELECT
*
FROM
todos
WHERE
todos.id in ( 1, 3, 2, 4 )
This returns:
1
2
3
4
But I want it to return in the same order as the provided id values, like this:
1
3
2
4
I've seen answers for MySQL and PostgreSQL but not for SQLite.
ORDER BY CASE id WHEN x THEN y
Found it in an obscure SQLite forum.
There's a neat way of ordering things that is very specific but lends itself to be programmatically generated.
To achieve the desired order, you can use the following:
SELECT
*
FROM
todos
WHERE
todos.id in ( 1, 3, 2, 4 )
ORDER BY
CASE todos.id
WHEN 1 THEN 1
WHEN 3 THEN 2
WHEN 2 THEN 3
WHEN 4 THEN 4
END
This returns the records in the following order:
1
3
2
4
As you can see, you're manually specifying the order of each record. This would be laborious if you were doing this manually, but this can be easily programmed and appended to a query, if you're using a programming language.
For example, I'm using this with Android/Java and ended up doing something like this to generate this ORDER BY clause:
String orderBy = "CASE todos.id ";
int i = 1;
for ( int id : ids ) {
orderBy = orderBy.concat( " WHEN " + id + "' THEN " + i );
i++;
}
orderBy = orderBy.concat( " END");
// Append `orderBy` to your normal SQLite query.
I am currently trying to improve on a query that is being used to build a view. The query is in PL/SQL, in an Oracle database. There are 3 different types of reports (100,200, and 300) that are generated at each building. We track the consecutive years that each report is generated, and based on the combination of (1) the type(s) of report(s) generated for a given year and (2) the consecutive years each report has been generated, we arrive at a Result type for that building.
Here is a description of the criteria for the Result types:
Result 600 - If all 3 report types have been generated in the current year, where:
Level 1: all reports were generated in 1 consecutive year (this is the first year)
Level 2: at least 1 report type has been generated for 2 consecutive years (none have 3 consecutive years)
Level 3: at least one report type has been generated for 3 consecutive years
Result 100 - Only report type 100 has been generated in the current year, where:
Level 1 - 1 consecutive year
Level 2 - 2 consecutive years
Level 3 - 3 consecutive years
Result 200 - Only report type 200 has been generated in the current year, where:
Level 1 - 1 consecutive year
Level 2 - 2 consecutive years
Level 3 - 3 consecutive years
Result 300 - Only report type 300 has been generated in the current year, where:
Level 1 - 1 consecutive year
Level 2 - 2 consecutive years
Level 3 - 3 consecutive years
Result 400 - Only reports 100 and 200 have been generated, where:
Level 1: both reports were generated in 1 consecutive year (this is the first year)
Level 2: at least 1 report type has been generated for 2 consecutive years (neither have 3 consecutive years)
Level 3: at least one report type has been generated for 3 consecutive years
Result 500 - Only reports 100 and 300 have been generated, where:
Level 1: both reports were generated in 1 consecutive year (this is the first year)
Level 2: at least 1 report type has been generated for 2 consecutive years (neither have 3 consecutive years)
Level 3: at least one report type has been generated for 3 consecutive years
Result 700 - Only reports 200 and 300 have been generated, where:
Level 1: both reports were generated in 1 consecutive year (this is the first year)
Level 2: at least 1 report type has been generated for 2 consecutive years (neither have 3 consecutive years)
Level 3: at least one report type has been generated for 3 consecutive years
Still with me? Sweet. So here is the current code that is used to generate this view, which is simply a display of the result:
CREATE OR REPLACE FORCE VIEW REPORTS.REPORT_RESULT_VIEW
(
BUILDING,
BUILDING_NAME,
GROUP,
YEAR,
TYPE,
SUBTYPE,
CONSEC,
RESULT
)
AS
WITH cte1
AS (SELECT 1 ID_100,
1 ID_200,
1 ID_300,
'600 Level 1' RESULT
FROM DUAL
UNION ALL
SELECT 2 ID_100,
2 ID_200,
2 ID_300,
'600 Level 2' RESULT
FROM DUAL
UNION ALL
SELECT 3 ID_100,
3 ID_200,
3 ID_300,
'600 Level 3' RESULT
FROM DUAL
UNION ALL
SELECT 1 ID_100,
1 ID_200,
2 ID_300,
'600 Level 2' RESULT
FROM DUAL),
(note - there are 63 total combinations that are listed in the actual code... I only entered the first few to give you an idea of how it is set up)
cte2
AS ( SELECT MAX (ID_100) ID_100_CONSEC,
MAX (ID_200) ID_200_CONSEC,
MAX (ID_300) ID_300_CONSEC,
YEAR,
BUILDING
FROM (SELECT CONSEC ID_100,
NULL ID_200,
NULL ID_300,
YEAR,
TYPE || SUBTYPE TYPE,
BUILDING
FROM REPORT_MASTER_VIEW
WHERE TYPE || SUBTYPE = '100'
UNION
SELECT NULL ID_100,
CONSEC ID_200,
NULL ID_300,
YEAR,
TYPE || SUBTYPE TYPE,
BUILDING
FROM REPORT_MASTER_VIEW
WHERE TYPE || SUBTYPE = '200'
UNION
SELECT NULL ID_100,
NULL ID_200,
CONSEC ID_300,
YEAR,
TYPE || SUBTYPE TYPE,
BUILDING
FROM REPORT_MASTER_VIEW
WHERE TYPE || SUBTYPE = '300')
GROUP BY YEAR, BUILDING),
cte3
AS (SELECT c2.*, c1.RESULT
FROM cte2 c2
JOIN
cte1 c1
ON NVL (c2.ID_100_CONSEC, 0) = c1.ID_100
AND NVL (c2.ID_200_CONSEC, 0) = c1.ID_200
AND NVL (c2.ID_300_CONSEC, 0) = c1.ID_300)
SELECT t1."BUILDING",
t1."BUILDING_NAME",
t1."GROUP",
t1."YEAR",
t1."TYPE",
t1."SUBTYPE",
t1."CONSEC",
t2.RESULT
FROM REPORT_MASTER_VIEW t1
JOIN
cte3 t2
ON t1.BUILDING = t2.BUILDING AND t1.YEAR = t2.YEAR
WHERE T1.TYPE IN ('100', '200' '300')
ORDER BY t1.BUILDING;
Now, because for every report combination, it has to run through all the possible combinations, this view takes about 24 seconds to build. In the app that it is referenced in, it takes nearly a minute to load the page. For this reason, I am trying to figure out ways to make the query more efficient. At first, I was thinking of using nested CASE statements, but I wasn't really sure how that would work. Any suggestions on how to better approach this is greatly appreciated.
WITH cte2 AS
(
SELECT MAX(CASE WHEN TYPE || SUBTYPE = '100' THEN CONSEC END) AS ID_100_CONSEC
, MAX(CASE WHEN TYPE || SUBTYPE = '200' THEN CONSEC END) AS ID_200_CONSEC
, MAX(CASE WHEN TYPE || SUBTYPE = '300' THEN CONSEC END) AS ID_300_CONSEC
, YEAR
, BUILDING
FROM REPORT_MASTER_VIEW
WHERE TYPE || SUBTYPE IN ('100', '200', '300')
GROUP BY
YEAR
, BUILDING
)
,cte3 AS
(
SELECT ID_100_CONSEC
, ID_200_CONSEC
, ID_300_CONSEC
, YEAR
, BUILDING
, CASE
WHEN c2.ID_100_CONSEC = 1 THEN '600 Level 1'
WHEN c2.ID_100_CONSEC = 2 THEN '600 Level 2'
WHEN c2.ID_100_CONSEC = 3 THEN '600 Level 3'
WHEN c2.ID_200_CONSEC = 1 THEN '600 Level 1'
WHEN c2.ID_200_CONSEC = 2 THEN '600 Level 2'
WHEN c2.ID_200_CONSEC = 3 THEN '600 Level 3'
WHEN c2.ID_300_CONSEC = 1 THEN '600 Level 1'
WHEN c2.ID_300_CONSEC = 2 THEN '600 Level 2'
WHEN c2.ID_300_CONSEC = 3 THEN '600 Level 3'
END AS RESULT
FROM cte2
WHERE c2.ID_100_CONSEC IN (1, 2, 3)
OR c2.ID_200_CONSEC IN (1, 2, 3)
OR c2.ID_300_CONSEC IN (1, 2, 3)
)
SELECT t1."BUILDING",
t1."BUILDING_NAME",
t1."GROUP",
t1."YEAR",
t1."TYPE",
t1."SUBTYPE",
t1."CONSEC",
t2.RESULT
FROM REPORT_MASTER_VIEW t1
WHERE T1.TYPE IN ('100', '200', '300')
AND EXISTS
(
SELECT 1
FROM cte3 t2
WHERE t1.BUILDING = t2.BUILDING
AND t1.YEAR = t2.YEAR
)
ORDER BY
t1.BUILDING;
Should be pretty close. I think you will need to polish it a little.