Writing a SQL conditional statement across columns for survey data - sql

I am working with survey data that is feeding directly into a Snowflake DB.
In the survey tool, the primary question is formatted with a scaled numeric 0 through 10 satisfaction question, and then a subsequent question asks for a written explanation/exposition, but that subquestion can be skipped/left unanswered.
Also, based on how the respondent responds and rates to the scaled question, the survey tool will change the subquestion ie What do you like most about our Waffles? or What could be better?
Each of the three unique questions -the primary scaled question and the two different subquestions- have their own unique QUESTIONID and survey participants have a unique ID as RESPONSEID.
I am attempting to collect survey responses from only participants that have answered both the primary question and their resulting subquestion regardless of which subquestion they were prompted, and ignoring participants that did not write/respond to their subquestions.
The current query and output looks like this:
SELECT DISTINCT
r.RESPONSEID,
r.QUESTIONID,
CASE
WHEN r.SURVEY = q.SURVEY AND r.questionid = q.QUESTIONID THEN q.QUESTIONTEXT
ELSE NULL
END QTEXT,
r.RESPONSE,
FROM RESPONSES r
JOIN QUESTIONS q ON q.questionid = r.questionid
JOIN QUESTION_RESPONSE s ON s.response_id = r.responseid
WHERE r.SURVEY IN ('WaffleSurvey3000')
AND (q.QUESTIONID = '1' OR q.QUESTIONID = '1A'
OR q.QUESTIONID = '1B')
AND QTEXT IS NOT NULL
ORDER BY RESPONSEID;
And output:
RESPONSEID QUESTIONID QTEXT RESPONSE
A 1 Between 0 and 10... 7
B 1 Between 0 and 10... 9
B 1A What did you like... Best Waffles EVER!
C 1 Between 0 and 10... 5
D 1 Between 0 and 10... 6
E 1 Between 0 and 10... 2
E 1B What could be better... Awful Waffles! Do better! SHAME
But would like an output that ignores participants that did not answer their prompted subquestion asking for text which would look like:
RESPONSEID QUESTIONID QTEXT RESPONSE
B 1 Between 0 and 10... 9
B 1A What did you like... Best Waffles EVER!
E 1 Between 0 and 10... 2
E 1B What could be better... Awful Waffles! Do better! SHAME
I was hoping I could pull this off with another WHERE clause at the end, but since this seems to be a conditional statement, I'm assuming it'll involve another CASE statement, but not sure.
Any thoughts?

Perhaps you can add to the where clause of your query another filter:
AND r.RESPONSEID = (
select p.RESPONSEID from RESPONSES p
group by p.RESPONSEID having COUNT(1) > 1
)
Another version:
AND r.RESPONSEID||SUBSTR(r.QUESTIONID,1,1) = (
select p.RESPONSEID||SUBSTR(p.QUESTIONID,1,1) from RESPONSES p
group by p.RESPONSEID||SUBSTR(p.QUESTIONID,1,1) having COUNT(1) > 1
)

Related

Return count id's value from multiple rows in one column Postgres

I'm having two tables (relation between themTest_case.id = Test_tag.test_id) like this:
Test_case table
id
name
1
Test name 1
2
Test name 2
3
Test name 3
4
Test name 4
Test_tag table
test_id
tag
1
feature:example1
1
package:Reports
1
QA
2
feature:example1
2
package:Reports
2
QA
3
feature:example1
3
package:Reports
3
QA
4
feature:newexample1
4
package:Charts
4
QA
The database tables and structure were already defined as I'm using a oublic library to push the results.
So, I need to return in the result the count of the id's and the value feature:example1
knowing that is a test that contains the tag package:Reports
So, it should return something like
Results
count(id)
tag
3
feature:example1
I already tried some different approaches without success.
How can I do that?
I think I'm as confused as everyone else, but this is a shot in the dark based on the various comments. There are much easier ways to arrive at this dataset, but I'm trying to read between the lines on your comments:
select
count (t.test_id), t.tag
from
test_case c
join test_tag t on c.id = t.test_id
where
t.tag like 'feature%' and
exists (
select null
from test_tag t2
where t2.test_id = t.test_id and t2.tag = 'package:Reports'
)
group by
t.tag

MS access join two tables, get unique rows

This is a modification to a previous question original answer , I hope the proper thing to do is start a new thread.
I have a table called Parts, PartRefID is the PK
PartRefID PartDefID AssemblyID
1 2 c63df10b-8250-4aa5-9889-9e8046331dbf
11 1 db51f4a8-3ffa-41f7-81c1-a9accbbb299a
67 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
77 5 38fa8b7a-2945-4546-8eab-7865a1e515b2
133 2 c63df10b-8250-4aa5-9889-9e8046331dbf
134 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
I need to extract rows with a unique AssemblyID. This was answered by GMB with the following sql:
select *
from parts as p
where [PartRefID] = (
select max(p1.[PartRefID])
from parts as p1
where p1.[AssemblyID] = p.[AssemblyID] and p1.[PartDefID] = 2
)
which worked beautifully. However requirements have changed and I must ignore the PartDefID field and there could also be AssemblyID's which represent parts I do not want.
The AssemblyID's shown in the above table represent an electrical connector part.
Electrical connector parts will ALWAYS have a Partclass of 1 which is defined in another table called PartDefinitions shown here:
PartDefID PartClass PartNumber
1 1 MS27467T23F55P
2 1 330-00186-09
3 2 336-00024-00
4 2 336-00022-00
5 1 MS27468T23F55S
6 1 330-00184-09
with my limited sql knowledge I decided a join was necessary and came up with the following code:
SELECT Parts.*, PartDefinitions.PartClass
From PartDefinitions
INNER Join Parts
On PartDefinitions.PartDefID = Parts.PartDefID
Where (((PartDefinitions.PartClass) = 1))
this gets me close, it produces all the parts in the parts table which are connectors. However there are some duplicate AssemblyID's.
what I need is to produce the following:
PartRefID PartDefID AssemblyID
1 2 c63df10b-8250-4aa5-9889-9e8046331dbf
11 1 db51f4a8-3ffa-41f7-81c1-a9accbbb299a
67 6 136fc5d8-7b65-41b5-bca3-7d4180a1e0ab
77 5 38fa8b7a-2945-4546-8eab-7865a1e515b2
my apologies if I have not made a clear and concise question
thanks for any help
and thanks again GMB
If I understand correctly, you want to filter by the PartClassId in both the subquery and the outer query:
select p.*, pd.PartClass
From Parts as p inner join
PartDefinitions as pd
on pd.PartDefID = p.PartDefID
where pd.PartClassId = 1 and
p.pPartRefID = (select max(p2.pPartRefID)
from parts as p2 inner join
PartDefinitions as pd2
on pd2.PartDefID = pd.PartDefID
where p2.AssemblyID = p.AssemblyID and
p2.PartClassId = 1
)

Finding Duplicate and Missing (null) Values in Oracle Table

I am looking for errors in a table and want to report both duplicates and missing values. I am unsure of the best way to do this and am looking for advice on a better way to accomplish this. This is in Oracle 12c.
This appears to achieve the desired result:
SELECT a.id,
a.mainfield,
a.location,
b.counter
FROM maintable a
INNER JOIN (
SELECT mainfield,
Count(*) counter
FROM maintable
GROUP BY mainfield
HAVING Count(mainfield) > 1 OR mainfield IS NULL
) b ON a.mainfield = b.mainfield OR
( a.mainfield IS NULL AND b.mainfield IS NULL )
ORDER BY a.mainfield;
This works and gives me the ID, the potentially null MAINFIELD, the location and a count of either the duplicate MAINFIELD values or the null MAINFIELD values.
Is there something simpler or potentially more efficient that I could be using? I have to admit that my SQL skills are quite rusty.
Sample data may or may not help, but the ID is the primary key, is a number and not nullable. The other fields are both NVARCHAR2 and nullable. None of those are indexed. Here is what the output could look like. Some records are outright errors. Some are obvious typos. Some appear to be test data.
ID MAINFIELD LOCATION COUNTER
------- --------- --------------------------------- -------
16626 206000650 9A OLIVER ST CENTRAL STATION 2
18805 206000650 3 SWIFT CT CENTRAL STATION 2
22409 940000170 2 MARKET ST NEWARK DE 2
22003 940000170 1 MARKET ST NEWARK NJ 2
29533 970000030 95 MILL RD ANDOVER 2
20256 970000030 12 RAILROAD AVE 2
29018 978900050 44 BROAD STREET 2
28432 978900050 WASHINGTON ST AND HAMILTON AVE 2
21831 980700050 BROADWAY NEWTOWN 2
24147 980700050 MAIN STREET LEVITTOWN 2
26418 3
26738 TEST DATA 3
26755 3
The last three rows have a null MAINFIELD and there are three such records (two of which have the location null also).
After adding some insight into the data above, I realized I might consider using NVL to eliminate part of the conditions, like this (assuming the value I chose would not be a valid value in the mainfield):
SELECT a.id,
a.mainfield,
a.location,
b.counter
FROM maintable a
INNER JOIN (
SELECT mainfield,
Count(*) counter
FROM maintable
GROUP BY mainfield
HAVING Count(mainfield) > 1 OR mainfield IS NULL
) b ON NVL(a.mainfield,'***NULL***') = NVL(b.mainfield.'***NULL***')
ORDER BY a.mainfield;
This executes a bit quicker and seems to produce the desired result. I have been trying other alternatives without success, so this may be the best alternative.
One alternative that I discarded which might be appropriate for a slightly different scenario (but was the worst performer for me) is this one:
SELECT id,
mainfield,
location,
COUNT (id) OVER (PARTITION BY mainfield) counter
FROM maintable a
WHERE mainfield IS NULL
OR EXISTS(SELECT 1 from maintable b
WHERE mainfield = a.mainfield AND ROWID <> a.ROWID)
ORDER BY a.mainfield;
I just really liked the way this was put together and was hopeful that it would be somewhat efficient. We are not talking that it runs for days, but I am trying to re-learn in Oracle what might have once been a skill back when I was coding with SQL/DS.
If any of the above gives anyone an idea of a better alternative, I am all ears. (For example, is there a way to reference the counter [the COUNT (id) over PARTITION BY mainfield] in the WHERE clause?)
Thanks again.
This seems to be a good compromise between readability and reliability and efficiency which was offered by Balazs Papp on the dba.stackexchange.com board:
https://dba.stackexchange.com/a/210998/154392
SELECT * FROM (
SELECT id,
mainfield,
location,
COUNT (id) OVER (PARTITION BY mainfield) counter
FROM maintable a
) where counter > 1 or mainfield IS NULL
ORDER BY mainfield;
This is a simplification of the last alternative of the original post. It does not appear to be more inefficient than my original alternative (as far as I can tell), but to me it is more readable.

Access SQL Syntax for Cross-Table Count

I have what may be a simple SQL syntax question but I've been scratching my head over it for weeks now and it's abstract enough that I'm having trouble hunting down the correct search in Google.
Let us assume that I have three tables: Users and Bookings:
Users:
UserID Name
1 Adam
2 Bob
3 Charlie
Bookings:
BookingID UserID MeetingID
1 1 1
2 2 1
3 2 2
4 3 2
The query that I'm looking to create will tell me how many other users each user has shared a meeting ID with. In my example:
Output:
UserID Co-Meeters
1 1
2 2
3 1
As in the example, users 1 and 3 only had one co-meeter (in this case "2") and user 2 had two co-meeters (1 and 3).
I'm sorry if my description isn't terribly clear, but I'm trying to strip out the needless complication from other intersecting tables and fields that don't really affect the syntax I'm looking for. My initial thought was to use "Group By", but since Bookings is a many-to-many (in terms of the fields I'm looking at) I can't make the logic work.
Any and all help is appreciated.
I think this should do the trick:
select u.userid, iif(isnull(x.others), 0, x.others) as [Co-Meeters]
from users u
left join bookings b on u.userid = b.userid
left join (
select meetingid, count(*) as others from bookings where userid <> u.userid
) x on b.meetingid = x.meetingid
order by 1

Oracle SQL How to find missing value for different users

I have 2 tables
One table with questions
ID Description
== ===========
1 Some Question
2 Some Question
3 Some Question
4 Some Question
And an other one with the awsers to each question of every users
ID_USER ID_QUESTION ANSWER
======= =========== =========
1 2 a
1 1 b
1 3 d
2 1 e
2 4 a
3 4 c
3 2 a
As you can see it is possible that a user does not answer a question and this is my problem
I am currently trying to find wich answer a user did not answer to.
I'd like to have something like this
ID_USER ID_MISSING_QUESTION
======= ===================
1 4
2 3
2 2
3 1
3 3
I can easly find the missing questions for a single user but i can't do that for every user since they are quite numerous.
Thanks Ayoye
Quick and Dirty:
SELECT TB_USER.ID, TB_QUESTION.ID AS "Q_ID" FROM TB_USER, TB_QUESTION
minus
SELECT ID_USER, ID_QUESTION FROM tb_answer
Sql Fiddle Demo here.
I think You are looking for something like this:
SELECT
u.id_user,
q.id_question
FROM
questions q
CROSS JOIN users u
LEFT JOIN answers a ON (a.id_question = q.id_question and a.id_user = u.id_user)
WHERE
a.answer IS NULL
First You shoyul create set of every question for every user, and then try to join in with Your answers. And then filer out all results that have found answers. :)
You should post the SQL statement(s) you tried, before expecting a full answer, else someone might think you want let others write all the code for you...
Nevertheless, instead of plain JOIN, use a FULL OUTER JOIN and a LEFT OUTER JOIN resp. RIGHT OUTER JOIN, depending on table ordering in your SQL statement (which you did not post yet), and filter with IS NULL.