For all future mysql support questions (whether on Stack Overflow or on Joomla Stack Exchange), you will enjoy more, faster and more accurate answers if you include a fiddle of your table schema in an online demo link. For example: db-fiddle
As for this specific task, RSForm's #__rsform_submission_values
table is built as a Unified Content Model. This means you will need to group related rows and use aggregate functions to filter and isolate what you need. This technique is commonly referred to as a PIVOT. You can find my other Joomla-related pivot queries on Joomla Stack Exchange.
I am rather surprised that your submission_values
table contains a user
column. This is not the standard table structure designed by RSForm. I am going to write my answer with the knowledge that the user column comes from a related table. I am going to show this best practice so that:
- you have an opportunity to un-hack your table structure if you have hacked it and
- researchers who have a standard table structure can immediately use my snippets.
There will be a few ways to execute the required technique. I will show a classic pivot query with an INNER JOIN
and another query that uses a subquery with EXIST
to isolate the unique counts. If Username
is not a unique field in the submissions
table, then find a unique field in that table to count. I have tested these queries and php scripts to be successful.
Raw Query via INNER JOIN:
SELECT COUNT(DISTINCT s.Username)
FROM lmonp_rsform_submissions s
INNER JOIN lmonp_rsform_submission_values sv
ON s.FormId = sv.FormId
AND s.SubmissionId = sv.SubmissionId
WHERE s.FormId = 16
GROUP BY s.Username
HAVING MAX(IF(FieldName = 'state', FieldValue, NULL)) = 'mystate1'
AND MAX(IF(FieldName = 'qda', FieldValue, NULL)) = 'myqad1'
AND MAX(IF(FieldName = 'city', FieldValue, NULL)) = 'mycity1'
Raw Query via EXISTS(subquery):
SELECT COUNT(1)
FROM lmonp_rsform_submissions s
WHERE s.FormId = 16
AND EXISTS (
SELECT FormId
FROM lmonp_rsform_submission_values sv
WHERE s.FormId = sv.FormId
AND s.SubmissionId = sv.SubmissionId
GROUP BY s.Username
HAVING MAX(IF(FieldName = 'state', FieldValue, NULL)) = 'mystate1'
AND MAX(IF(FieldName = 'qda', FieldValue, NULL)) = 'myqad1'
AND MAX(IF(FieldName = 'city', FieldValue, NULL)) = 'mycity1'
)
Now, I'll present the Joomla query builder syntax to generate the above queries.
Both snippets will share these variables as a means to allow you to customize the sql conditions without scanning through the full query block.
$formId = 16;
$having = [
'state' => 'mystate1',
'qda' => 'myqad1',
'city' => 'mycity1'
];
Joomla Query Builder with INNER JOIN:
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select("COUNT(DISTINCT s.Username)")
->from("#__rsform_submissions s")
->innerJoin("#__rsform_submission_values sv ON s.FormId = sv.FormId AND s.SubmissionId = sv.SubmissionId")
->where("s.FormId = " . $formId)
->group("s.Username");
foreach ($having as $column => $value) {
$query->having("MAX(IF(FieldName = " . $db->q($column) . ", FieldValue, NULL)) = " . $db->q($value));
}
//echo $query->dump(); // uncomment to see the rendered sql
$db->setQuery($query);
echo $db->loadResult();
Joomla Query Builder with EXISTS(subquery):
$db = JFactory::getDbo();
$subquery = $db->getQuery(true)
->select("FormId")
->from("#__rsform_submission_values sv")
->where(["s.FormId = sv.FormId", "s.SubmissionId = sv.SubmissionId"])
->group("s.Username");
foreach ($having as $column => $value) {
$subquery->having("MAX(IF(FieldName = " . $db->q($column) . ", FieldValue, NULL)) = " . $db->q($value));
}
$query = $db->getQuery(true)
->select("COUNT(1)")
->from("#__rsform_submissions s")
->where(["s.FormId = " . $formId, "EXISTS ($subquery)"]);
//echo $query->dump(); // uncomment to see the rendered sql
$db->setQuery($query);
echo $db->loadResult();
I did not benchmark these queries, so if you find one of them to be noticeably slow, you might try the other.
@itoctopus/@itoctopus seems rather scathing of use of DISTINCT, so it may be less performant.