Selecting from a table where field = this and value = that - sql

I have a mysql table that looks something like this:
Row 1:
'visitor_input_id' => int 1
'name' => string 'country'
'value' => string 'Canada'
Row 2:
'visitor_input_id' => int 1
'name' => string 'province'
'value' => string 'Alberta'
Row 3:
'visitor_input_id' => int 1
'name' => string 'first_name'
'value' => string 'Jim'
The problem is that I need to be able to filter it so that a user can generate reports using this:
filter 1:
'field_name' => string 'country'
'field_operator' => string '='
'field_value' => string 'Canada'
filter 2:
'field_name' => string 'province'
'field_operator' => string '!='
'field_value' => string 'Alberta'
filter 3:
'field_name' => string 'first_name'
'field_operator' => string '%LIKE%'
'field_value' => string 'Jim'
I am not really sure what the query would look like to be able to select from this using the filters. Any suggestions? (Unfortunately, creating a new table to store the data more sanely is not really feasible at this time because it is already full of user data)
I think it would look something like this:
if(field_name = 'province' THEN ADD WHERE field_value != 'Alberta')
if(field_name = 'country' THEN ADD WHERE field_value = 'Canada')
if(field_name = 'first_name' THEN ADD WHERE field_value LIKE '%jim%')
but I am not sure how that would work...

Turns out that this seems to work:
SELECT * FROM visitor_fields
INNER JOIN visitor_inputs ON (visitor_inputs.input_id = visitor_fields.input_id)
INNER JOIN visitor_fields as filter_0
ON (filter_0.input_id=visitor_inputs.input_id
AND filter_0.field_name = 'province'
AND filter_0.field_value != 'Alberta')
INNER JOIN visitor_fields as filter_1
ON (filter_1.input_id=visitor_inputs.input_id
AND filter_1.field_name = 'country'
AND filter_1.field_value = 'Canada')
INNER JOIN visitor_fields as filter_2
ON (filter_2.input_id=visitor_inputs.input_id
AND filter_2.field_name = 'first_name'
AND filter_2.field_value LIKE '%jim%')

I know you say creating a new table with a better schema isn't feasible, but restructuring the data would make it more efficient to query and easier to work with. Just create a new table (called visitor in my example). Then select from the old table to populate the new visitor table.
vistor
----------------
vistor_id
firstname
province
country
You could loop through the statement below with any scripting language (PHP, TSQL, whatever scripting language you're most comfortable with). Just get a list of all vistor_id's and loop through them with the sql below, replacing the x with the visitor_id.
INSERT INTO visitor (visitor_id, name, province, country) VALUES X,
(SELECT value FROM old_table WHERE name='first_name' AND vistor_id = x),
(SELECT value FROM old_table WHERE name='province' AND vistor_id = x),
(SELECT value FROM old_table WHERE name='country' AND vistor_id = x);
This will produce a table where all a visitor's data is on a single row.

Are you able to create an SQL string and then execute it? The string would look like this:
SELECT * FROM yourtable
WHERE (name='country' AND value='Canada') AND
(name='province' AND value!='Alberta') AND
(name='first_name' AND value LIKE '%jim%)
EDIT:
I see. Multiple records. So try joining them. This is not correct SQL syntax but should look similar:
SELECT * FROM
(SELECT * FROM yourtable WHERE (name='country' AND value='Canada'))
JOIN on visitor_input_id
(SELECT * FROM yourtable WHERE (name='province' AND value!='Alberta'))
JOIN on visitor_input_id
(SELECT * FROM yourtable WHERE (name='first_name' AND value LIKE '%jim%))

Related

Display a formatted version of a returned query value

I am trying to figure out the best way to go about a problem I'm having with our Database. I don't have the option to go back and change the architecture, and so I am stuck trying to figure out a workaround.
Table 1:
User => Column MailingCountry = Either (en-Country(en-US), Country (US), or Null)
Table 3:
SMSCode => Column CountryCode = en-Country (en-US), Column SMSCode = Code (1 for US).
I'd like to know if there is a way that I could:
Get the User.MailingCountry and check if it is in the format of 'en-US', 'US' or 'NULL'
If it is in 'en-US' we are good, if it is in 'US', I'd like to replace it in the returned results to 'en-US', and if it is 'NULL', id like it to default to 'en-US'.
Inner JOIN with SMS.CountryCode where User.MailingCountry = SMS.CountryCode and then retrieve the SMSCode.
I guess the problem is, I am not sure how I can do something like
Select m.MailingCountry, a.SMSCode FROM User m->
IF (m.MailingCountry = 'US' or m.MailingCountry is null) Then m.MailingCountry = 'en-US'
Inner Join SMSCode a on a.CountryCode = m.MailingCountry
You can go for below query:
SELECT SMS.SMSCode
FROM
(SELECT CASE WHEN MailingCountry like '%US%' OR MailingCountry IS NULL THEN 'en-US'
ELSE MailingCountry END AS MailingCountry
FROM User) AS u
INNER JOIN SMSCode AS SMS
ON SMS.CountryCode = u.MailingCountry

Translate this Linq into SQL

I have this linq code that I need to translate into identical SQL so I can query the database directly... I get stuck when it gets complicated. Can anyone help?
Linq
_db.BatchPaymentSplits
.Where(bps => bps.YearSetupId == i.YearSetupId)
.Where(bps => bps.CustomerIdEntered != null)
.Where(bps => _db.BatchPayments
.Where(bp => _db.Batches.Where(b => b.BatchTypeId.Equals("T"))
.Select(b => b.BatchId)
.Contains(bp.BatchId)
)
.Select(bp => bp.BatchPaymentId).Contains(bps.BatchPaymentId)
)
SQL so far
SELECT * FROM BatchPaymentSplit
WHERE YearSetupId = 1
AND CustomerIdEntered IS NOT NULL
I can't say that I think the LINQ or the resulting SQL is the best way to express this query (should be using Join I think), but this is my literal translation:
SELECT *
FROM BatchPaymentSplits bps
WHERE bps.YearSetupId = i.YearSetupId AND
bps.CustomerIdEntered IS NOT NULL AND
EXISTS (SELECT * FROM BatchPayments bp
WHERE EXISTS (SELECT * FROM Batches b
WHERE b.BatchTypeId = 'T' AND
b.BatchId = bp.BatchId) AND
bp.BatchPaymentId = bps.BatchPaymentId)
You can translate Contains when applied to an IEnumerable/IQueryable as an EXISTS query with an = expression.

How to escape parameter in like sql query using active record?

Have query with parentesis:
SELECT *
FROM users
WHERE company_id = 1 AND (
name LIKE "%smith%" OR
last_name LIKE "%smith%"
)
But in codeigniter have:
$query_members = $this->db
->select('users.*')
->from('users')
->like(array('users.names' => $search))
->or_like(array('users.last_name' => $search))
->where(array('users.company_id' => 1));
This generate:
SELECT *
FROM users
WHERE
name LIKE '%smith%' OR
last_name LIKE '%smith%' AND
company_id = 1;
And does not works, i need ((a or b) and c), not (a or b and c). I found solution here: Codeigniter parentheses in dynamic Active Record query but the variable is escaped with full quotes, i need escape with "%" pre and pos value. I have this:
$search_escaped = $this->db->escape($search);
$query_members = $this->db
->select('users.*')
->from('users')
->where('(users.names LIKE "%'.$search_escaped.'%" OR users.last_name LIKE "%'.$search_escaped.'%")')
->where(array('members.company_id' => (int)$company_id));
But the query add bad quotes:
SELECT `users`.*
FROM `users`
WHERE (users.names LIKE "%'smith'%" OR users.last_name LIKE "%'smith'%")
AND `members`.`company_id` = 2
The "%'smith'%" is bad quoted. How I can solve this by using active record of codeigniter 3.0.0?

TYPO3 doesn't respect field names in JOIN query

I'm trying to fetch a JOIN query in TYPO3 using createQuery and $query->statement(...), but get odd results. Can someone explain to me why TYPO3 doesn't include table names as a prefix to column names in a JOIN query? Does this conflict with the ORM? Can I in anyway speed up a query of multiple 1:N-relations?
Example:
SELECT
client.name, project.name
FROM
client
LEFT JOIN
project ON project.client = client.uid
The PHP code from client repository:
$query = $this->createQuery();
$query->statement($statement);
$query->getQuerySettings()->setReturnRawQueryResult(true);
var_dump($query->execute());
The result prints out only names of the projects:
array (size=294)
0 =>
array (size=1)
'name' => string 'Projectname1' (length=21)
1 =>
array (size=1)
'name' => string 'Projectname2' (length=20)
2 =>
array (size=1)
'name' => string 'Projectname3' (length=32)
EDIT: This might be standard SQL behaviour.
Use aliases for fields:
SELECT
client.name client_name, project.name project_name
FROM
client
LEFT JOIN
project ON project.client = client.uid

join with AND id=1 with SQL::Abstract::More

I'm trying to do a join using SQL::Abstract::More that has an `and and then a literal value, not on a table column.
=>{table.table_id=table_id,table_log.date>table.date,table_log.event_id=1}
gd_audit_log
the resulting output that I want
LEFT OUTER JOIN table_log ON (
table_log.date > table.date
AND table.table_id = table_log.table_id
AND table_log.event_id = 1
)
this code works except for
AND table_log.event_id = 1
the error is
... failed: Unknown column 'table_log.1' in 'on clause'
obviously it's generating the wrong SQL, what I'm trying to figure out is how to get it to generate the SQL I need.
From RT Bug 84972. To insert a literal value, you need to use the hashref syntax, instead
of the string syntax :
my $result = $sqla->join(
'table',
{ operator => '=>',
condition => { '%1$s.table_id' => {-ident => '%2$s.table_id'},
'%2$s.date' => {'>' => {-ident => '%1$s.date'}},
'%2$s.event_id' => 1}},
'table_log'
);
Seems to me that table_log.event_id = 1 isn't a valid join clause, but should be in a where clause.
Use force Luke
qw/table
=>{table.table_id=table_id,table_log.date>table.date,table_log.event_id='1'}
table_log/
need 'escape' 1 by single quote