Getting duplicate count and data from table - php

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.

Related

Query Select and Show All First Table And Second Table Even is not Exist in Second Table

SAMPLE TABLE
TABLE FIRST_TABLE
| rid | requirements |
| 1 | 2x2 pic |
| 2 | valid id |
| 3 | 137 form |
| 4 | app form |
Second table
| id | applicant_id | rid | remarks |
| 1 | 1 | 1 | pass |
| 2 | 1 | 2 | pass |
| 3 | 2 | 1 | pass |
How to select all records from first table and show even the data is not exist on second table.
Result should be like this.
applicant_id | rid | remarks |
1 | 1 | pass |
1 | 2 | pass |
1 | 3 | null |
1 | 4 | null |
this is my sample code.
select requirements from first_table
left join second_table on first_table.rid = second_table.rid
where second_table.applicant_id = 1
group by first_table.rid
//result :
applicant_id | rid | remarks |
1 | 1 | pass |
1 | 2 | pass |
You just need to move the second_table.applicant_id = 1 to the join.
select requirements, first_table.rid, remarks
from first_table
left join second_table on
first_table.rid = second_table.rid and
second_table.applicant_id = 1
group by first_table.rid
http://sqlfiddle.com/#!9/a0cffdd/17

Select last value doctrine query

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.

MySQL MIN() limit by column

I have a MySQL table that is formatted as follows:
group_clue:
---------------------------------------------------
| id | group_id | clue_id | completed | run_order |
---------------------------------------------------
| 1 | 1 | 2 | 1 | 1 |
| 2 | 1 | 6 | 1 | 2 |
| 3 | 1 | 4 | 1 | 3 |
| 4 | 1 | 3 | 0 | 4 |
| 5 | 1 | 1 | 0 | 5 |
| 6 | 1 | 5 | 0 | 6 |
| 7 | 2 | 9 | 1 | 1 |
| 8 | 2 | 2 | 0 | 2 |
...
---------------------------------------------------
The data above in the group_clue is constructed such that each group_id has every clue_id at some run_order (ranging from 1 to the number of clue_ids and not repeating for a particular group).
First Question
I want to create a table showing the first clue_id for each group_id where completed = 0 when ordered by run_order (aliased as current_clue). Using the above example, this would give:
---------------------------
| group_id | current_clue |
---------------------------
| 1 | 3 |
| 2 | 2 |
---------------------------
My preliminary attempt is:
SELECT group_id, MIN(clue_id) as current_clue
FROM group_clue
WHERE completed = 0
GROUP BY group_id
However, this returns the same clue_id for each group_id.
Second Question
From the data in the first question, I would like to compose a final table where I GROUP_CONCAT() these results so that it contains every current_clue and each group_id that contains that current_clue. I would also like it ordered from those clues with the most group_ids to those with the fewest. An example resulting table is:
--------------------
| clue | group_ids |
--------------------
| 3 | 1,5,4,3 |
| 2 | 2,6 |
--------------------
I cannot figure out the ordering. My preliminary attempt is:
SELECT clue_id, GROUP_CONCAT(group_id)
FROM [resulting_table]
GROUP BY clue_id
ORDER BY [something]
Any help is appreciated: what queries would fit this scenario?
The first part of your question can be solved this way (it expects that run_order is unique per group):
SELECT t1.group_id,
t1.clue_id AS current_clue
FROM group_clue t1
INNER JOIN (SELECT group_id,
MIN(run_order) as run_order
FROM group_clue
WHERE completed = 0
GROUP BY group_id) t2 USING (group_id, run_order)
The logic of this query is pretty simple:
The inner query selects the pairs of group_id and the corresponding minimal value of run_order which has the completed = 0.
After that we join the original table to this set of pairs so that we could select the corresponding clue_id additionally.
You can sort by number of elements per group using
ORDER BY COUNT(*) DESC

Multiple select and condition by column

I am trying to figure out how to select an item from table by his column name p.e.
strucutre looks like this
table items
id | name | column_1 | column_2 | column_3 |
1 | nm1 | 1 | 4 | 7,8 |
2 | nm2 | 2,3 | 4 | 9 |
3 | nm3 | 3,1 | 4 | 7 |
table columns
id | c_name |
1 | cnm1 |
2 | cnm2 |
3 | cnm3 |
table column_values
id | c_id | value |
1 | 1 | abcd |
2 | 1 | cdbh |
3 | 1 | dsff |
4 | 2 | wewe |
5 | 2 | cgbh |
6 | 2 | cdlh |
7 | 3 | adbh |
8 | 3 | qdbh |
9 | 3 | pdbh |
So when I wanted to find "abcd" I tried
"SELECT a.* FROM items a, columns b, column_values c WHERE c.`value` LIKE '%abcd%' GROUP BY a.`id`"
but I knew this will find nothing without any conections so i went further
"SELECT a.* FROM items a, columns b, column_values c WHERE c.`value` LIKE '%abcd%' AND b.`id` = c.`c_id` GROUP BY a.`id`"
still no proper connection with item
and here is the problem there is a changing amount of columns and the name contains id of the column and value is set of ids of column values.
So i need to select item by his name which is "name+"column_id in column_values by FIND IN SET cause if i look for abcd it is id 1 and there are two items which have id 1 in column_1
item 1 and item 2
ALSO id of values are AI so there is not possibility of duplicate so there is no need to check of column_id to search in proper column in item table
it can work something like for from 0 - 30 p.e. and it will search in column_1, column_2 column_3 until 30 for id match

Merge Rows AND/OR Columns into one field in a GROUP BY

My SQL table looks like
+-----+------------+--------------+--------------+-----------+------------+-----------+
| rid | ship_to_id | product_code | product_name | first_row | second_row | third_row |
+-----+------------+--------------+--------------+-----------+------------+-----------+
| 1 | 555 | A | Crystal | 1 | 2 | 3 |
| 1 | 555 | A | Crystal | 4 | 5 | 6 |
| 2 | 333 | B | Diamond | first | second | third |
| 2 | 333 | A | Crystal | ROW 1 | ROW 2 | ROW 3 |
| 2 | 333 | A | Crystal | ROW 4 | ROW 5 | ROW 6 |
+-----+------------+--------------+--------------+-----------+------------+-----------+
And I am trying to get following results
+-----+------------+--------------+-------------------------------------+
| rid | ship_to_id | product_name | data |
+-----+------------+--------------+-------------------------------------+
| 1 | 555 | Crystal | 1 2 3 4 5 6 |
| 2 | 333 | Diamond | first second third |
| 2 | 333 | Crystal | ROW 1 ROW 2 ROW 3 ROW 4 ROW 5 ROW 6 |
+-----+------------+--------------+-------------------------------------+
Can someone please tell me what is wrong with my code. Thanks
$query = mysql_query("SELECT * FROM mytable group by rid, ship_to_id, product_code, product_name");
while($row = mysql_fetch_array($query)) {
echo "$row[rid] $row[ship_to_id] $row[product_code] $row[product_name] $row[first_row] $row[second_row] $row[third_row] <br>";
}
You're forgetting product_code sometimes, I guess.
This probably is bad database design. You should learn about Database normalization and related techniques.
Third, SQL normally produces the same number of columns for every result record, so the best result you could have has rows like 1, 555, "A", "Crystal", "1 4 2 5 3 6" (notice these are 5 values). But I cannot think of a concatenation method that would produce the numbers in the 1 2 3 4 5 6 order. Depending on the better form of your database-schema-to-be, this might be something easier done in PHP than SQL.
If you're still up to concatenating all values into a single cell (as in the newly formatted example output), the you should try something along these lines:
SELECT
rid, ship_to_id, product_code, product_name,
GROUP_CONCAT(CONCAT(first_row,'#',second_row,'#',third_row) SEPARATOR '~') AS data
FROM tablename
GROUP BY rid, ship_to_id, product_code, product_name;
Notice that the values of first_row etc. are separated by a '#' and the values from distinct records by a '~' sign. You can find more options in the documentation of MySQL's GROUP_CONCAT().
you can try something like
select rid,ship_to_id,product_name,
GROUP_CONCAT(CONCAT(first_row,' ',second_row,' ',third_row) as new_val
from mytable
group by rid,ship_to_id,product_name;
As you group by the first 4 columns and use no aggregation function on the remaining ones, data will be lost when multiple record have the same values in the columns grouped by.
So basically the result will be like the following:
+-----+------------+--------------+------------------------------------+
| rid | ship_to_id | product_name | first_row | second_row | thrid_row |
+-----+------------+--------------+------------------------------------+
| 1 | 555 | Crystal | 1 | 2 | 3 |
| 2 | 333 | Diamond | first | second | third |
| 2 | 333 | Crystal | ROW 1 | ROW 2 | ROW 3 |
+-----+------------+--------------+------------------------------------+
That's what group by means. To keep the data of the fields containing varying data, you must use an aggregation function on them, like GROUP_CONCAT. Example:
SELECT rid, ship_to_id, product_code, product_name, GROUP_CONCAT(first_row), GROUP_CONCAT(second_row), GROUP_CONCAT(third_row)
FROM mytable
GROUP BY rid, ship_to_id, product_code, product_name
This will concatenate the values of the corresponding record like this:
+-----+------------+--------------+------------------------------------------+
| rid | ship_to_id | product_name | first_row | second_row | thrid_row |
+-----+------------+--------------+------------------------------------------+
| 1 | 555 | Crystal | 1 4 | 2 5 | 3 6 |
| 2 | 333 | Diamond | first | second | third |
| 2 | 333 | Crystal | ROW 1 ROW 4 | ROW 2 ROW 5 | ROW 3 ROW 6 |
+-----+------------+--------------+------------------------------------------+
However, your approach with GROUP BY is probably not be the best for this case. It would worth to think about to just order by the rid, ship_to_id, product_code, product_name columns, and then iterate through them in PHP with the given order and merge the corresponding rows there.
You may also have to reconsider you database design, as a query like this smells about a bad concept :)

Categories