You Asked
I would like your help with SQL to drive a report on customer survey responses. The main problem is needing to account for responses that were NOT given.
-- Dim table containing all potential survey responses
--
create table survey_response_dim
( survey_response_dim_pk number(10)
, survey_name char(8)
, question_code char(4)
, response_code char(4)
, response_descr varchar2(60));
-- Fact table containing customer survey responses
--
create table cust_survey_resp_fct
( customer_pk number(10)
, survey_response_dim_pk number(10)
, response_date date);
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 1, 'S1', 'Q1', 'F', 'FEMALE' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 2, 'S1', 'Q1', 'M', 'MALE' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 3, 'S1', 'Q2', 'A', '0-10' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 4, 'S1', 'Q2', 'B', '11-30' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 5, 'S2', 'Q1', '1', 'Strongly Agree' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 6, 'S2', 'Q1', '2', 'Agree' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 7, 'S2', 'Q1', '3', 'Disagree' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 8, 'S2', 'Q1', '4', 'Strongly Disagree' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 9, 'S1', 'Q3', 'Y', 'Yes' );
INSERT INTO survey_response_dim
( survey_response_dim_pk, survey_name, question_code, response_code, response_descr )
VALUES ( 10, 'S1', 'Q3', 'N', 'No' );
-- Fact table containing customer survey responses
--
create table cust_survey_resp_fct
( customer_pk number(10)
, survey_response_dim_pk number(10)
, response_date date);
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 10, 2, to_date('05/21/2004', 'mm/dd/yyyy') );
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 10, 4, to_date('05/21/2004', 'mm/dd/yyyy') );
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 20, 3, to_date('05/21/2004', 'mm/dd/yyyy') );
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 30, 2, to_date('05/21/2004', 'mm/dd/yyyy') );
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 30, 3, to_date('05/21/2004', 'mm/dd/yyyy') );
INSERT INTO cust_survey_resp_fct
( customer_pk, survey_response_dim_pk, response_date )
VALUES ( 40, 6, to_date('05/22/2004', 'mm/dd/yyyy') );
Select sd.survey_name, sd.question_code
, sd.response_code, count(*) as responders
from cust_survey_resp_fct s
, survey_response_dim sd
where s.survey_response_dim_pk = sd.survey_response_dim_pk
group by sd.survey_name, sd.question_code, sd.response_code
SURVEY_NAME QUESTION_CODE RESPONSE_CODE RESPONDERS
S1 Q1 M 2.00
S1 Q2 A 2.00
S1 Q2 B 1.00
S2 Q1 2 1.00
I would like to also account for responses that were NOT given. The report would look similar to:
SURVEY_NAME QUESTION_CODE RESPONSE_CODE RESPONDERS
S1 Q1 F 0.00
S1 Q1 M 2.00
S1 Q2 A 2.00
S1 Q2 B 1.00
S1 Q3 N 0.00
S1 Q3 Y 0.00
S2 Q1 2 1.00
You addressed a similar issue (missing dates in a transaction table) in a recent article in Oracle Magazine but I just didn't "get" it. Hopefully, I'll clue in this time. Thanks for your help.
and Tom said...
You need a table of customer ids and survey question ids -- all combinations. We'll outer join to that and you'll get them all.
I have to assume in your schema, these objects already exist, if not, you'll need to supply the data somehow. We need distinct customer ids:
ops$tkyte@ORA9IR2> drop table cust;
Table dropped.
ops$tkyte@ORA9IR2> create table cust
2 as
3 select distinct customer_pk from cust_survey_resp_fct;
Table created.
we already have the survey question ids (the primary key of the survey response dim table) so we can cartesian product them in to X below: ops$tkyte@ORA9IR2> Select sd.survey_name, sd.question_code
2 , sd.response_code, count(s.customer_pk) as responders
3 from cust_survey_resp_fct s,
4 survey_response_dim sd,
5 (select survey_response_dim.survey_response_dim_pk, cust.customer_pk from survey_response_dim,cust) X
6 where s.survey_response_dim_pk (+) = x.survey_response_dim_pk
7 and s.customer_pk (+) = x.customer_pk
8 and sd.survey_response_dim_pk = x.survey_response_dim_pk
9 group by sd.survey_name, sd.question_code, sd.response_code
10 /
SURVEY_N QUES RESP RESPONDERS
-------- ---- ---- ----------
S1 Q1 F 0
S1 Q1 M 2
S1 Q2 A 2
S1 Q2 B 1
S1 Q3 N 0
S1 Q3 Y 0
S2 Q1 1 0
S2 Q1 2 1
S2 Q1 3 0
S2 Q1 4 0
10 rows selected.
In 10g, you'll have partitioned outer joins for doing the same -- without the cartesian product:
</code>
https://asktom.oracle.com/Misc/oramag/on-uniqueness-space-and-numbers.html <code>
Rating
(3 ratings)
Is this answer out of date? If it is, please let us know via a Comment