Select last value doctrine query - php

My table looks something like this
id | name | revision_number | form_key | locked
---------------------------------------------------
1 | Name1 | 1 | abcd | true
2 | Name2 | 1 | efgh | false
3 | Name1 | 2 | abcd | true
4 | Name2 | 2 | efgh | true
5 | Name2 | 3 | efgh | true
Now I want to get the forms that were locked last, bases on form_key, so in this case the one with id = 3 and name = Name1 and the one with id = 5 and name = Name2
This is the query I currently have
$revisionQuery =$em->getRepository('AppBundle:Form')->createQueryBuilder('f')
->select('f')
->where('f.lockBit = :locked')
->andWhere('f.revisionNumber = (SELECT MAX(f2.revisionNumber) FROM AppBundle:Form f2 WHERE f.formKey = f2.formKey GROUP BY f2.formKey)')
->setParameters(['locked' => true]);
But this doesn't give me the results I want.

I give to you the SQL for do it. I think you are going to need a Native DQL for Doctrine
SELECT
f.id,
f.`name`,
f.revision_number,
f.form_key
FROM
form f
INNER JOIN (
SELECT
max(ff.revision_number) AS revision,
ff.form_key
FROM
form ff
GROUP BY
ff.form_key
) tt ON f.form_key = tt.form_key
AND f.revision_number = tt.revision
Hope this help you.

Related

PHP: Best practise / API Function to consolidate SQL data 1:N to a 2d array

I often come across a situation where I have a 1:N relation, e.g. a table of items and another table with additional metadata / attributes for every item.
Consider this example:
users
+-----------+-----------+
| user_id | username |
+-----------+-----------+
| 1 | max |
| 2 | john |
| 3 | elton |
| 4 | tom |
| 5 | dave |
+-----------+-----------+
user_profile_data
+-----+-----------+-----------+
| uid | field_id | field_val |
+-----+-----------+-----------+
| 1 | 1 | a |
| 1 | 2 | b |
| 2 | 1 | c |
| 2 | 2 | d |
| 3 | 1 | e |
| 3 | 2 | f |
| 3 | 3 | g |
| 4 | 1 | h |
| 4 | 4 | i |
+-----+-----------+-----------+
Now I have two questions:
I want to select extended user-data, every (uid, field_id) combination is unique, usually I do it this way:
SELECT u.user_id, u.username, upd.field_id, upd.field_val
FROM users u
LEFT JOIN user_profile_data upd ON u.user_id = upd.uid
I get a row for every user/field combination and would need to "re-sort" in php because usually I want to have an array which contains every User with a Subarray of extended attributes, for example like this:
$users = array(1 => array('username' => max, 'data' => array(1 => 'a', 2 => 'b')), 2 => array('username' => 'john', ...));
Is there a standardized way of simplifying this and/or what's the best-practise in such cases? Is there already something build-in in PHP (not an external SQL framework)?
Thanks
Something like this should work (didn't test, sorry)
$users = [];
foreach($results as $result) { // assuming $results contains DB results
if (!isset($users[$result['user_id']])) {
$user[$result['user_id']] = [];
$user[$result['user_id']]['username'] = $result['username'];
$user[$result['user_id']]['data'] = [];
}
$user[$result['user_id']]['data'][$result['field_id']] = $result['field_val'];
}
This is not generic code, you should adapt it for each table schema, but I do not know a simplier way to do it. Or you spam your SQL server by not doing "JOIN" query... :/ (I think your sql is better :) )

Comparing tables in MySQL and adding a yes/no response

Can someone help me tweak my SQL to get the desired result. I have a table of users, a table of cases, and a relationship table for users attached to cases.
Users Table - users
+----+-------+--------+
| id | first | last |
+----+-------+--------+
| 1 | Joe | Bloggs |
| 2 | John | Doe |
| 3 | Jane | Doe |
| 4 | Dave | Smith |
+----+-------+--------+
Case Table - cases
+----+--------+------+
| id | Case | Code |
+----+--------+------+
| 1 | Case 1 | C1 |
| 2 | Case 2 | C2 |
| 3 | Case 3 | C3 |
+----+--------+------+
Case Users Table - case_users
+----+---------+---------+
| id | case_id | user_id |
+----+---------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 4 |
| 4 | 3 | 1 |
| 5 | 1 | 4 |
+----+---------+---------+
I want to query the database to return me a full list of users and return a yes or no if they are linked to case 1 and then case 2 case 3 etc.
The SQL I've got so far (selecting for Case ID 1) returns all users but is assigning 'no' to everyone:
SELECT
users.first,
users.last,
CASE WHEN case_users.case_id IS NULL THEN 'N' ELSE 'Y' END AS 'yes/no'
FROM
users
LEFT OUTER JOIN case_users ON case_users.case_id = 1
My actual result is:
+-------+--------+--------+
| First | Last | Yes/No |
+-------+--------+--------+
| Joe | Bloggs | Y |
| John | Doe | Y |
| Jane | Doe | Y |
| Dave | Smith | Y |
+-------+--------+--------+
My desired result should be:
+-------+--------+--------+
| First | Last | Yes/No |
+-------+--------+--------+
| Joe | Bloggs | Y |
| John | Doe | Y |
| Jane | Doe | N |
| Dave | Smith | Y |
+-------+--------+--------+
Can someone help me as I can't get the desired result?
You're missing the join condition from users to case_users:
SELECT
users.first,
users.last,
CASE WHEN case_users.case_id IS NULL THEN 'N' ELSE 'Y' END AS 'yes/no'
FROM
users
LEFT OUTER JOIN case_users ON users.id = case_users.user_id AND case_users.case_id = 1
You can try this one.
SELECT u.first, u.last, IF(cu.case_id,'Y','N') AS CASE_1 FROM users u
LEFT JOIN case_users cu ON u.id = cu.user_id AND cu.case_id = 1
Can use IF(cu.case_id,'Y','N')condition also instead of CASE
SELECT u.*
, CASE WHEN cu.case_id IS NULL THEN 'N' ELSE 'Y' END linked
FROM users u
JOIN cases c
LEFT
JOIN case_users cu
ON cu.user_id = u.id
AND cu.case_id = c.id
WHERE c.id = 1;

how to count the mysql data when match rules

I would like to do a show how many promotion code left function.
I already find out how to query the latest promotion. now i would like to show the code how many left.
Now I have 2 table,
this is t1.
+--------------+--------------------------+----------------------+
| id | name | description |
+--------------+--------------------------+----------------------+
| 1 | GG | GG is good |
| 2 | ABC DEFG | ABC DDDDD |
| 3 | CCARD | Gooooo |
+--------------+--------------------------+----------------------+
this is t2
+---------+------------+-------------------+------------------+
| id | kaid | code | timestamp |
+---------+------------+-------------------+------------------+
| 1 | 2 | ZZZZAAAAA | 123456789 |
| 2 | 2 | AAAZZADWWW | 123344444 |
| 3 | 1 | ASFASDFFFF | 123333333 |
| 4 | 2 | HHHHHFDFG | 123222222 |
| 5 | 1 | ASDASDADDDD | 123111111 |
| 6 | 1 | AAAAAAAA | |
| 7 | 1 | DGDFGDSFG | |
+---------+------------+-------------------+------------------+
I query the latest user get promotion code like this
$querylist = mysql_query("SELECT t2.*,t1.name FROM t2,t1 where t1.id = t2.kaid ORDER BY t2.timestamp desc limit 5");
while($rowlist = mysql_fetch_row($querylist)) {
$idlist[] = $rowlist['id'];
$user_list_latest[] = $rowlist;
}
After I loop query, I will get the data like this
1. GG
2. ABC DEFG
3. GG
4. ABC DEFG
5. ABC DEFG
Then I would like to show the count like this.
Hypothesis the count data is $countleft
1. GG (This promotion code only 2 left!)
2. ABC DEFG (This promotion code only 0 left!)
3. GG (This promotion code only 2 left!)
4. ABC DEFG (This promotion code only 0 left!)
5. ABC DEFG (This promotion code only 0 left!)
the number 2 and 0 is $countleft.
the t2 timestamp is means the user get the valid promotion code time. so the timestamp empty means nobody get yet.
Change your query to this and try
select name,balance from t1 join
(SELECT kaid,COUNT(ID) as balance FROM t2
WHERE isnull(timestamp) GROUP BY kaid)t3
on (kaid=t1.id) ORDER BY balance desc limit 5;
In the loop print every row and column(there is only two column for each row). It will give the answer.

DISTINCT values for two columns in MySQL

I have a table with contents like the following:
+----+-----------+---------+--------+------+
| id | text_from | text_to | text | seen |
+----+-----------+---------+--------+------+
| 1 | A | B | Hello1 | 0 |
| 2 | X | Y | Hello2 | 1 |
| 3 | Y | X | Hello3 | 1 |
| 4 | B | A | Hello4 | 1 |
+----+-----------+---------+--------+------+
It is a conversation like A sends a text to B, B sends to A etc. How can I get the DISTINCT conversation? For example, distinct conversation between A and B, or X and Y etc.
I want to get something like
+----+-----------+---------+--------+------+
| id | text_from | text_to | text | seen |
+----+-----------+---------+--------+------+
| 1 | A | B | Hello1 | 0 |
| 2 | X | Y | Hello2 | 1 |
+----+-----------+---------+--------+------+
If once text_from and text_to has two unique values, it can not be repeated. For example, if there is text_from = A, text_to = B, the table should not have text_from = B, text_to = A.
I am trying several methods for DISTINCT and GROUP BY since a few hours, but could not figure out any solution! Any suggestions would be greatly appreciated.
Seems like a simple NOT EXISTS should do the trick. Example SQL Fiddle
select *
from table t
where not exists (
select 1
from table t1
where
(
(t.text_from = t1.text_from
and t.text_to = t1.text_to)
or (t.text_from = t1.text_to
and t.text_to = t1.text_from)
) and t.id > t1.id
)

Getting duplicate count and data from table

I have 3 tables like this:
table_1
+-ID-+-table_3_id-+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
+----+------------+
table_2
+-ID-+-table_1_id-+-name--+-value-+
| 1 | 1 | Name1 | Data1 |
| 2 | 1 | Name2 | Data2 |
| 3 | 1 | Name3 | Data3 |
| 4 | 2 | Name1 | Data1 |
| 5 | 2 | Name2 | Data4 |
| 6 | 2 | Name3 | Data5 |
| 7 | 3 | Name1 | Data6 |
| 8 | 3 | Name2 | Data2 |
+----+------------+-------+-------+
table 3 consists of IDs and other data that is irrelevant to this question. However, I need to be able to filter on table_3_id.
This is what I need:
Table 2 has multiple rows that have information of the rows in table_1. I need to have a query that checks if there are duplicates in the 'data' column, which have the same 'name'. The result I need would be this (with a WHERE table_3_id = 1):
+-table_3_id-+-name--+-value-+-duplicate-+
| 1 | Name1 | Data1 | true |
| 1 | Name2 | Data2 | false |
| 1 | Name3 | Data3 | false |
+------------+-------+-------+-----------+
Or, if possible, only return the data from table_2 where it actually is a duplicate. The 'duplicate' field can be a count too, since I do know the amount of rows that have the same table_3_id.
I hope I have made my question clear enough. If it is not clear enough I will try to improve it. I have tried it with joins and subqueries, but my knowledge of SQL isn't enough to make an advanced query like this. I'd prefer this in a single query instead of multiple in PHP.
You can use something along the lines of the below:
select Name
from table
group by name
having count(*) > 1
You need to check for every row in Table_2, if there are duplicates. This can be done with a subquery, like this:
SELECT
B.Table_3_ID
,A.Name
,A.Value
,(SELECT COUNT(*) FROM Table_2 C
WHERE C.Name = A.Name AND C.Value = A.Value)
AS DuplicateCount
FROM Table_2 A
INNER JOIN Table_1 B
ON A.Table_1.ID = B.ID
There may be some errors in my SQL, especially the table aliases, because I have no syntax check at the moment, but the principle should work.

Categories