1

I am trying to get some information from a table, when a (one or more than one) condition(s) is(are) met but this conditions are stored in other table.

Here is a screenshot of the 3 tables:

tables

So I need a query to do this:

  1. Given a Status (IDStatus) and an Action (IDAction)
  2. If there is an IDCondition (it can be NULL, one, or more than one)

    A. If there is one, use the IDocField as a column from a table called IDoc, using ConditionOperator as the condition (read this as =, <, >) and the value on ConditionValue.

    B. If there are more than one, the same as before, but use each condition with AND.

    C. If it is NULL, directly go to point 3

  3. Get Subject, SendTo, CC, CCO, and FileTemplate that matched all of the above explained.

I want to try this because it would reduce my C# code, but if this is too complex or not plausible, I will do multiple queries like what I explained above.

I am asking this, because I am not sure how to get multiple conditions in a SELECT. I mean by this:

If there is more than one condition, how can I execute them or get all of them in a single query but that has all the returning things on point 3 ?

Example:

SELECT * 
FROM WF_MailCondition 
WHERE IDCondition = 1

this will return all conditions (keys can repeat) that has IDCondition equal to 1. But then I have to use all the three columns to create a condition like ID = 1 been ID in IDocField, = in ConditionOperator and 1 in ConditionValue.

I know there is some inconsistencies in the image, like IDCondition is NN (not null) but I said that it can be null (I am fixing this things).

My SQL:

SELECT 
    Subject, SendTo, CC, CCO, FileTemplate 
FROM 
    WF_Mail AS M
INNER JOIN 
    WF_MailStatusAction AS S ON S.IDMail = M.IDMail
WHERE 
    (SELECT "HERE SELECT THE 3 COLUMNS TO USE A CONDITION" FROM WF_MailCondition WHERE IDCondition = S.IDCondition)
    AND (S.IDAction = "ACTION FROM OUTSIDE" AND S.IDStatus = "STATUS FROM OUTSIDE")

How to do the SELECT "HERE SELECT 3 COLUMNS..." and if the IDCondition is NULL directly get the columns requested in the first SELECT (Subject, SendTo, etc.)

The "ACTION FROM OUTSIDE" is a parametrized statement.

Forget about foreign keys, we are not using it (boss' decisions...).

I am doing this because is for an "event" thing. I call a method in my C# code that will see if there are mails to send. But this mails can have none, one or more than one conditions. This is to have more options than all have to send a mail. Maybe in the workflow there is no need to send email but in code is "hardcoded" so with this I am totally free to do what I need about that feature.

Maybe all of this can be a function or a stored procedure but I am very ignorant about that and performance with them.

If you need more info, please tell me.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
matiaslauriti
  • 7,065
  • 4
  • 31
  • 43
  • 1
    Whenever you start storing queries in the database you should take a step back and yourself if this is really a good idea. It is potentially vulnerable to sql injection and as you are discovering is incredibly difficult to work with. – Sean Lange Nov 21 '16 at 17:08
  • Yes, I know, but is the requirements, I cant change it, it came from the top... I said the same but couldnt change it :S – matiaslauriti Nov 21 '16 at 17:10

2 Answers2

0

I would suggest the following: - Create a QueryBuilder Class Where you have methods like:

* AddSelect()
* AddFrom()
* AddWhere()
* ToString()
...

And then use the "middlelayer" to handle the query cunstruction based on the conditions That way you have the most control over everything going on

Jester
  • 3,069
  • 5
  • 30
  • 44
0

From what I understand, I would write a query like this:

select m.subject, m.cc 
from wf_mail m
where exists (select 'true' 
            from wf_mailstatusaction s, wf_mailcondition c
            where s.idmail=m.idmail
            and s.idcondition = c.idcondition
            and c.idocfield||c.conditionoperator||c.conditionValue = 'id>500'
            group by s.idcondition
            having count(s.idcondition) = 1)
or exists (select 'true' 
            from wf_mailstatusaction s, wf_mailcondition c
            where s.idmail=m.idmail
            and s.idcondition = c.idcondition
            and c.idocfield||c.conditionoperator||c.conditionValue IN ('id>500', 'id<200')
            group by s.idcondition
            having count(s.idcondition) > 1)
or exists (select 'true'
            from wf_mailstatusaction s
            where s.idmail=m.idmail
            and s.idcondition is null)
donlys
  • 440
  • 6
  • 13
  • It is not exactly what i need, but you helped me a lot with the query. What is missing are the `IDStatus` and `IDAction` conditions, and what i mean by multiple or not conditions is that i read table where conditions are stored, say `IDocField` = `ID` (this ID value refers to a table called `IDoc` that has a column called `ID`) and concat that with `ConditionOperator` = `=` and `ConditionValue` = `1`, so the query would also eavluate that `IDoc.ID = 1`. If you have multiple conditions you write all of this with `AND`. Thats a tricky part that I dont know if I can execute in a same query. – matiaslauriti Nov 21 '16 at 18:58
  • when you have having count(s.idcondition) > 1 it will work on minimum two status records for mail - and assuming that conditionvalue is unique per mail-status, you will have two different conditions matched by s.conditonValue IN ('value2', 'value3'). So you are in a way getting AND - isn't that correct? – donlys Nov 21 '16 at 19:12
  • That condition is not IN ('value2', 'value3'). I have to concatenate `IDocField`, `ConditionOperator` and `ConditionValue` to form a `WHERE` clause, for example `IDocField` = `Column1`, `ConditionOperator` = `>` and `ConditionValue` = `500`, it will form a `WHERE` clause saying `Column1 > 500`. That is why I am using `WF_MailCondition`. And when you do `S.ConditionValue`, this column is not in `S`, is in `WF_MailCondition` so, should I use `INNER JOIN` or just `FROM` ? Do you understand now ? Thanks you ! – matiaslauriti Nov 21 '16 at 19:32
  • Not at all, when you do `and c.conditionoperator||c.conditionValue = '>500'` what does `||` mean ? Is it `OR` ? If the anwers is yes you are not following me :P I have to concatenate `IDocField`, `ConditionOperator` and `ConditionValue` to make it a literal where clause. I have to concatenate each value of that column and make a WHERE on that result. And on multiple Conditions, I have to read all `IDCondition`s and do the same as I explained. If I have a final condition of `ID = 1` and other condition that is `Column1 > 500` it should be `... WHERE ID = 1 AND Column1 > 500` – matiaslauriti Nov 21 '16 at 19:50
  • In sql you cannot use values stored in columns as actual column names. What you can though however is something I have shown in the query. So you can also add c.idocfield to the left side of the express and compare it with the right side literal value. As I mentioned earlier, when you have a scenario with multiple statuses, let's say for an idmail you have 2 statuses - 1->idcondition=100 and 2->idcondition=200. Now let's say idcondition100=id, >, 500 and idcondition200=id,<,200. In this case IN will match and you will have correct resultset. – donlys Nov 21 '16 at 20:09
  • so there is no interpretation of > or < in the query - you will have to provide those as part of literals. – donlys Nov 21 '16 at 20:33
  • Thank you everyone, so it is not really posible what I am trying to do in a single query, thanks ! – matiaslauriti Nov 22 '16 at 13:57
  • One more thing you should look into is use of case statement in where clause. You can use it to check if operator is > then... etc. See http://stackoverflow.com/questions/87821/sql-if-clause-within-where-clause – donlys Nov 22 '16 at 14:07
  • 1
    Also review http://stackoverflow.com/questions/14588228/build-queries-from-table-column-names-stored-in-a-table and http://stackoverflow.com/questions/12808189/setting-column-values-as-column-names-in-the-sql-query-result – donlys Nov 22 '16 at 14:46
  • Mmmm, the first URL is my approach, so I should use EXEC and all of that... thank you very much. I saw that but it's too complex than writing C# code. – matiaslauriti Nov 22 '16 at 18:25