2

I am trying to create a SELECT statement that requires multiple WHERE conditions. Is that possible. Here is the scenario. I have a table with the following structure.

FormID (Type Int)
SubmissionID (Type Int)
FieldName (Type text)
FieldValue (Type text)

The data would be something like this. Table Name: SubmissionsValue

FormID - SubmissionID - FieldName - FieldValue 
24 ------ 5 ---------- username ------ johnk
24 ------ 5 ---------- firstname ------ John
24 ------ 5 ---------- lastname ------ King 
24 ------ 5 ---------- address ------ 100 some street 
24 ------ 5 ---------- email ------ johnemail@gma.com 

24 ------ 9 ---------- username ------ cathym 
24 ------ 9 ---------- firstname ------ Catherine 
24 ------ 9 ---------- lastname ------ Mirusia 
24 ------ 9 ---------- address ------ 100 some other street 
24 ------ 9 ---------- email ------ cathyemail@gma.com

32 ------ 20 ---------- username ------ johnk
32 ------ 20 ---------- firstname ------ John
32 ------ 20 ---------- lastname ------ King 
32 ------ 20 ---------- address ------ 100 some street 
32 ------ 20 ---------- email ------ johnemail@gma.com
32 ------ 20 ---------- AdultTicket------ 5
32 ------ 20 ---------- SingleTicket------ 3
32 ------ 20 ---------- Total ------ $60.00

Apparently this is an Entity-Attribute-Value (EAV) design, I have been told!

As you can see the "FieldName", "FieldValue" etc are the actual names of the Fields of the table. Also entries from multiple forms from a same user can appear in the table. So my keyfield are the user emailID and the formID.

Then fieldnames are stored in the table along with it's fieldvalue for each online form.

Therefore "username", "firstname", "lastname", "address" and "email" are the actual fields in form and when the User submit their information, it gets stored in the table as shown above.

I want to show the details of the User in another area using their emailID as the key field.

Essentially this is what has to happen ($user->email gives the email of the current User):

SELECT username WHERE (FieldName = "email") AND (FieldValue = " $user->email")

But in reality to get the values "johnk" and "cathym" in my example, what it seems that I have to do is the following but I am not sure how to code that:

SELECT FieldValue WHERE (FieldName = "username") 
       (WHERE (FieldName = "email")
       AND (FieldValue = " $user->email")) 

Can someone please help me with this scripting?

This is for a Joomla site using RSForm!Pro. RSForm!Pro stores the form input in the above manner!!!

=== EDIT ====

Clarification: The table data shown above is all from one table. I just added a space between the two sets of data for readability.

You can essentially ignore FormID and SubmissionID. The backend keeps the entries from various different forms all in one table and therefore, it tracks the formID and the submissionID. So you can see that there will be various formID and submissionID in that table, eventually.

In this example, the data was entered from the same form, but two different submissions - 5 & 8.

In this case, I simply want to autopopulate the fields of a new form with the information of the User who is logged in.

Last Name: John King
User Address: 100 Some Street
etc...
rpacdn
  • 21
  • 3
  • what is emailID? Is that the email address? can you edit your question to show us what your input and desired output would be? You've shown us the incorrect output, so now show the intended results. – Martin Sep 03 '16 at 15:22
  • And what's going on with FormId, is it intended to be the same for everyone? – Martin Sep 03 '16 at 15:24
  • [The answer here](http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) provides advice on how to avoid SQL injection. Question about question: you want to select the username from the table when the FieldValue is the user's email and the FieldName is either the username or the email? –  Sep 03 '16 at 15:30
  • If you like, consider following this simple two-step course of action:1. If you have not already done so, provide proper CREATE and INSERT statements (and/or an sqlfiddle) so that we can more easily replicate the problem. 2. If you have not already done so, provide a desired result set that corresponds with the information provided in step 1. – Strawberry Sep 03 '16 at 15:38
  • @Terminus fair enough, I think i'd not acknowledged in my head the PHP variable when re skim reading the OPs SQL. – Martin Sep 03 '16 at 15:47
  • @Terminus, yes I want to find the Last Name, First Name etc of the User who is logged in at the time. But given the structure of the table, I have first find the fieldName "username" and then find it's fieldValue, WHERE the User's email macthes the fieldValue of the fieldName "email". – rpacdn Sep 03 '16 at 17:11
  • @rpacdn Martin's answer should solve it for you. If it did, be sure to accept his answer if it solves the problem. –  Sep 03 '16 at 17:57

4 Answers4

2

You can self join the table:

SELECT t2.FieldValue FROM <table> t1 
       INNER JOIN <table> t2 ON t1.formId = t2.formId 
       WHERE t1.fieldName = 'email' 
         AND t1.fieldValue = '$user->email' 
         AND t2.fieldName = 'username'

I think this will give you the desired result, it is self joining the same table, so you are able to return the correct values. I can't test this right now unfortunately but hopefully this is what you're after.

Basically the table can only return x number of rows, and the rows can't reference other returned rows (as far as I know), so instead of referencing Null values, the table is set to self-join (t1, t2) on the FormId value (the connection between all associated rows) so for each FormId the data to be checked by the WHERE clause is already all of the rows for each FormId.

This is impossible in your current SQL because you don't know the formID and have no way of finding it (It could possibly also be done with a sub-select, but I didn't entertain that route).

So the first part of the new SQL returns the whole block for where FormId = number, and then checks that block for where the email address = name@whatever and then returns the corresponding username, in this example.

I hope this helps.


Please also research Prepared Statements and how to correctly code PHP and SQL without leaving your database open to abuse and risk. Please read this link posted by Terminus. PHP The Right Way Is also a very good reference for this subject.

Community
  • 1
  • 1
Martin
  • 22,212
  • 11
  • 70
  • 132
  • Is supposed to be replaced with my actual table name?
    – rpacdn Sep 05 '16 at 18:21
  • well, yes, as you had not given your table name when I answered your question. You would do well to learn the Syntax for MySQL `:-)` – Martin Sep 05 '16 at 18:23
1

One possibility to solve this is to use subqueries.

SELECT t.FieldValue
FROM table t
WHERE t.FormID = (
  SELECT min(FormID)
  FROM table
  WHERE (FieldName = "email")
    AND (FieldValue = "$user->email")
) AND t.SubmissionID = (
  SELECT min(SubmissionID)
  FROM table
  WHERE (FieldName = "email")
    AND (FieldValue = "$user->email")
) AND t.FieldName ="username"

Another possibility is to join the table with itself.

SELECT u.FieldValue
FROM table u
  JOIN table e ON u.FormID = e.FormID
    AND u.submissionID = e.submissionID
WHERE e.FieldName ="email"
  AND e.FieldValue = "$user->email"
  AND u.FieldName = "username"

The subquery - solution could be slower depending on how well MySQL optimizes the query.

mm759
  • 1,404
  • 1
  • 9
  • 7
  • Sorry, it happens unfortunately that multiple people write similar answers at the same time. It seems that we had the same idea. – mm759 Sep 03 '16 at 15:41
  • I posted my answer, and saw your answer, and you hadn't mentioned self joining tables, then a few minutes later you edit your answer to add self joining tables. Looks rather like you saw my answer and wanted to copy it into your own `:-p`. I'm not to bothered but if you only considered it from reading my answer I think a note of acknowledgement is polite. Anyhow, these comments explain it `:-)`. No worries – Martin Sep 03 '16 at 15:46
  • If submissionValues is the name of my table, should I write the code as below: SELECT FieldValue FROM submissionValues t1, (SELECT FormID, SubmissionID FROM table WHERE FieldName='email' AND FieldValue = '$user->email') t2 WHERE t1.SubmissionID = t2.SubmissionID AND t1.FormId = t2.FormID AND t1.FieldName = 'username' (Aaarghhh... I am having a hard time getting the linefeed and indentation to format my comments in a more readable format also!) – rpacdn Sep 05 '16 at 18:22
  • @rpacdn: This is another solution that will probably work, too. The SELECT - clause is missing "t1". – mm759 Sep 06 '16 at 06:20
  • @Martin: I had both solutions in mind, wrote down the first, submitted it and then decided to add the second one, too. – mm759 Sep 06 '16 at 06:22
1

Data set

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(formID INT NOT NULL             -- Cannot be NULL
,SubmissionID INT NOT NULL       -- Cannot be NULL
,FieldName VARCHAR(20) NOT NULL  -- Cannot be NULL
,FieldValue VARCHAR(100) NOT NULL -- Could be NULL. Whether or not this can be NULL has important consequences for some of what follows!!
,PRIMARY KEY(formid,submissionid,fieldname)
);

INSERT INTO my_table VALUES
(24,5,'username', 'johnk'),
(24,5,'firstname','John'),
(24,5,'lastname', 'King'),
(24,5,'address', '100 some street'),
(24,5,'email', 'johnemail@gma.com'),
(24,9,'username', 'cathym'),
(24,9,'firstname','Catherine'),
(24,9,'lastname', 'Mirusia'),
(24,9,'address', '100 some other street'),
(24,9,'email','cathyemail@gma.com');

E.g.:

SELECT x.formid
     , x.submissionid
     , MAX(CASE WHEN fieldname = 'username' THEN fieldvalue END) username
     , MAX(CASE WHEN fieldname = 'firstname' THEN fieldvalue END) firstname
     , MAX(CASE WHEN fieldname = 'lastname' THEN fieldvalue END) lastname
     , MAX(CASE WHEN fieldname = 'address' THEN fieldvalue END) address
     , MAX(CASE WHEN fieldname = 'email' THEN fieldvalue END) email
  FROM my_table x
 GROUP 
    BY formid
     , submissionid
HAVING email = 'johnemail@gma.com';

+--------+--------------+----------+-----------+----------+-----------------+-------------------+
| formid | submissionid | username | firstname | lastname | address         | email             |
+--------+--------------+----------+-----------+----------+-----------------+-------------------+
|     24 |            5 | johnk    | John      | King     | 100 some street | johnemail@gma.com |
+--------+--------------+----------+-----------+----------+-----------------+-------------------+

or

SELECT x.formid
     , x.submissionid
     , x.fieldvalue email
     , MAX(CASE WHEN y.fieldname = 'username' THEN y.fieldvalue END) username
     , MAX(CASE WHEN y.fieldname = 'firstname' THEN y.fieldvalue END) firstname
     , MAX(CASE WHEN y.fieldname = 'lastname' THEN y.fieldvalue END) lastname
     , MAX(CASE WHEN y.fieldname = 'address' THEN y.fieldvalue END) address
  FROM my_table x
  JOIN my_table y
    ON y.formid = x.formid
   AND y.submissionid = x.submissionid
   AND y.fieldname <> x.fieldname
 WHERE x.fieldname= 'email'
   AND x.fieldvalue = 'johnemail@gma.com'
 GROUP 
    BY formid
     , submissionid
     , email;

+--------+--------------+----------+-----------+----------+-----------------+-------------------+
| formid | submissionid | username | firstname | lastname | address         | email             |
+--------+--------------+----------+-----------+----------+-----------------+-------------------+
|     24 |            5 | johnk    | John      | King     | 100 some street | johnemail@gma.com |
+--------+--------------+----------+-----------+----------+-----------------+-------------------+

or

SELECT email.formid
     , email.submissionid
     , email.fieldvalue email
     , username.fieldvalue username
     , firstname.fieldvalue firstname
     , lastname.fieldvalue lastname
     , address.fieldvalue address
  FROM my_table email
  LEFT
  JOIN my_table username
    ON username.formid = email.formid
   AND username.submissionid = email.submissionid
   AND username.fieldname = 'username'
  LEFT
  JOIN my_table firstname
    ON firstname.formid = email.formid
   AND firstname.submissionid = email.submissionid
   AND firstname.fieldname = 'firstname'
  LEFT
  JOIN my_table lastname
    ON lastname.formid = email.formid
   AND lastname.submissionid = email.submissionid
   AND lastname.fieldname = 'lastname'
  LEFT
  JOIN my_table address
    ON address.formid = email.formid
   AND address.submissionid = email.submissionid
   AND address.fieldname = 'address'
 WHERE email.fieldname = 'email'
   AND email.fieldvalue = 'johnemail@gma.com';

+--------+--------------+-------------------+----------+-----------+----------+-----------------+
| formid | submissionid | email             | username | firstname | lastname | address         |
+--------+--------------+-------------------+----------+-----------+----------+-----------------+
|     24 |            5 | johnemail@gma.com | johnk    | John      | King     | 100 some street |
+--------+--------------+-------------------+----------+-----------+----------+-----------------+

EDIT:

If you just want to return all 'fields' associated with a given user submission, that could be as follows, but note that common user data would normally be held inside a dedicated table, even, I'm sure, when using a framework like Joomla:

SELECT a.* 
  FROM my_table a 
  JOIN my_table b 
    ON b.formid = a.formid 
   AND b.submissionid = a.submissionid 
 WHERE b.fieldname = 'email' 
  AND b.fieldvalue = 'johnemail@gma.com';
+--------+--------------+-----------+-------------------+
| formID | SubmissionID | FieldName | FieldValue        |
+--------+--------------+-----------+-------------------+
|     24 |            5 | address   | 100 some street   |
|     24 |            5 | email     | johnemail@gma.com |
|     24 |            5 | firstname | John              |
|     24 |            5 | lastname  | King              |
|     24 |            5 | username  | johnk             |
+--------+--------------+-----------+-------------------+
Strawberry
  • 33,750
  • 13
  • 40
  • 57
0

First, get the formId and SubmissionId corresponding to the email in a subquery and get the username from the obtained formId and SubmissionId

SELECT FieldValue FROM table t1, 
       (SELECT FormID, SubmissionID FROM table 
        WHERE FieldName='email' AND FieldValue = '$user->email') 
t2 WHERE t1.SubmissionID = t2.SubmissionID 
        AND t1.FormId = t2.FormID 
        AND t1.FieldName = 'username'
Martin
  • 22,212
  • 11
  • 70
  • 132
prasanth
  • 3,502
  • 4
  • 28
  • 42
  • @Martin, is table in the above code to be replaced with the actual table name. If SubmissionValues is my actual table name, how should the above code be written? Is t1 and t2 just table handles? (Sorry, I am a newbie in SQL scripting) – rpacdn Sep 05 '16 at 18:36
  • Yeah you should replace `table` with the actual table names. t1 and t2 are aliases which can be anything – prasanth Sep 09 '16 at 22:24