I have the following setup:
A table with columns a, b, c.
An array with a random number of items (i1, i2, i3,... in).
Table contains rows like
1 1 i1
1 1 i2
. . .
. . .
. . .
1 1 in
1 2 i1
. . .
. . .
. . .
2 1 i1
2 2 i2
The thing is that not all records are there. For example row 1 2 i1 might be missing.
What I would like to do, from query (without getting all rows and iterate through them) is to see IF any row is missing (I don't care witch one, only IF one is missing).
This is a very simplified example for a much more complex problem so if I didn't expose it clear, or I forgot to mention anything feel free to ask for details.
A select and process in PHP is acceptable, as long as I don't select everything in table (although I don't see how to do this by processing data without selecting all but felt like it worth mentioning).
Some of you asked for a pattern so...:
Let's simplify some more... let's say column one has an array of possible data that can be found there, same for column 2, and already said it for column 3. All possible combinations between the 3 of then should be found on the table. I need to know if any are missing...
assuming you know he values for column a and b you could try the following:
select c, count (*) group by c;
this would tell you how many entries for each value are there.
i1 3
i2 0
in 3
then you could iterate over that result to see whats missing
Assume we have a table with this data.
mysql> SELECT * FROM stuff;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 1 | i1 |
| 1 | 1 | i2 |
| 1 | 2 | i2 |
| 1 | 2 | i3 |
| 2 | 1 | i1 |
+------+------+------+
5 rows in set (0.00 sec)
Lets also assume that all possible values for C is in the table. Then we can construct a reference table like this.
mysql> SELECT a,b,c FROM (SELECT DISTINCT a,b FROM stuff) t1 CROSS JOIN (SELECT DISTINCT c FROM stuff) t2;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 1 | i1 |
| 1 | 2 | i1 |
| 2 | 1 | i1 |
| 1 | 1 | i2 |
| 1 | 2 | i2 |
| 2 | 1 | i2 |
| 1 | 1 | i3 |
| 1 | 2 | i3 |
| 2 | 1 | i3 |
+------+------+------+
9 rows in set (0.00 sec)
We can then compare the table with actual data and the reference table by joining them together like this and get all missing rows like this:
mysql> SELECT * FROM stuff RIGHT JOIN (SELECT a,b,c FROM (SELECT DISTINCT a,b FROM stuff) t1 CROSS JOIN (SELECT DISTINCT c FROM stuff) t2) r ON stuff.a = r.a AND stuff.b = r.b AND stuff.c = r.c WHERE stuff.a IS NULL;
+------+------+------+------+------+------+
| a | b | c | a | b | c |
+------+------+------+------+------+------+
| NULL | NULL | NULL | 1 | 2 | i1 |
| NULL | NULL | NULL | 2 | 1 | i2 |
| NULL | NULL | NULL | 1 | 1 | i3 |
| NULL | NULL | NULL | 2 | 1 | i3 |
+------+------+------+------+------+------+
4 rows in set (0.00 sec)
The RIGHT JOIN ON a,b,c will match the rows in the reference table r against the actual rows. The missing rows will manifest as NULL on stuff side. Therefore we can get all missing rows by selecting any row with a NULL field in the stuff table.
Edit: You can change the SELECT * ... in the last query to SELECT count(*) ... and you get the number of missing rows in this case 4.
You can do this with a simple count. The number of expected rows is the number of distinct elements in A times the number of distinct elements in B times the number of distinct elements in C.
To count the number that are missing, just do arithmetic on the appropriate values:
select (cnt - cntA*cntB*cntC) as NumMissingRows
from (select count(distinct a) as cntA,
count(distinct b) as cntB,
count(distinct c) as cntC,
count(*) as cnt
from t
) t
What about such a query, this might not be the best performance but for a one time task this should work.
SELECT t1.id,
(
SELECT t2.id FROM table t2 WHERE t2.id < t1.id ORDER BY t2.id DESC LIMIT 1
) as prv
FROM table t1
HAVING id <> prv + 1
I would think about doing it this way, which will still work even if there are duplicates in your list of values. This sames doing any looping over the resulting fields (just a single row comes back which will tell you how many unique in your array are not found on the table.
SELECT COUNT(*)
FROM (SELECT 'i1' AS aCol
UNION
SELECT 'i2' AS aCol
UNION
SELECT 'i3' AS aCol
UNION
.......
UNION
SELECT 'in' AS aCol) Sub1
LEFT OUTER JOIN aTable
ON Sub1.aCol = aTable.c
WHERE aTable.c IS NULL
Could also be modified very easily to bring back a list of the items that are not found should that be required in the future.
Related
I work with PHP and PDO.
So I have 2 tables like,
Table 1
| id | name | age |
| 1 | John | 25 |
| 2 | Tom | 32 |
| 3 | James| 45 |
Table 2
| id | Comment | Link |
| 1 | some text | 3 |
| 2 | some text | 3 |
| 3 | some text | 1 |
So, Link column numbers represent id's in table1. For example Link = 3s in table 2 represent James in table 1. I need a query which brings all table1's data and also a number of repeated value for related Link column which comes from table2.
For example, the query should give me (let's choose James),
| id | name | age | Value |
| 3 | James | 45 | 2 |
value=2, because there are two 3s in link column which related to James
I tried somethings but got lots of errors.
I think you just need the GROUP BY
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
GROUP BY a.id, a.name, a.age
If you really want just one row then add WHERE
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
WHERE a.name = 'James'
GROUP BY a.id, a.name, a.age
or use subquery
SELECT a.id,
a.name,
a.age,
(SELECT count(*) FROM table2 b WHERE a.id = b.link) as value
FROM table1 a
WHERE a.name = 'James'
I want to select each available entry for each column once. This problem was solved with
SELECT DISTINCT a from my_table
UNION
SELECT DISTINCT b from my_table
UNION
SELECT DISTINCT c from my_table
UNION
SELECT DISTINCT d from my_table
in this question: MySQL SELECT DISTINCT multiple columns
I want to go further and use the same WHERE statements on each subquery. Is there any way without defining the WHERE each time? My current query would look like this:
SELECT DISTINCT a from my_table WHERE a='a' AND b=1 AND c='.' AND d='ab'
UNION
SELECT DISTINCT b from my_table WHERE a='a' AND b=1 AND c='.' AND d='ab'
UNION
SELECT DISTINCT c from my_table WHERE a='a' AND b=1 AND c='.' AND d='ab'
UNION
SELECT DISTINCT d from my_table WHERE a='a' AND b=1 AND c='.' AND d='ab'
All parameters don't have to be given, I just want to show the maximum that has to be possible. Is there any way to write this shorter?
I use PHP with doctrine, if that is any help.
Thanks in advance!
Example:
my_table:
a | b | c | d
-----+-----+-----+-----
a | 0 | . | ab
b | 0 | - | ag
a | 1 | . | cfd
c | 1 | . | b
a | 1 | - | ab
c | 1 | - | cfd
should give this result (without where statement):
a | b | c | d
-----+-----+-----+-----
a | 0 | . | ab
b | 1 | - | ag
c | | | cfd
| | | b
And with WHERE b=0 statement:
a | b | c | d
-----+-----+-----+-----
a | 0 | . | ab
b | | - | ag
EDIT: changed subqueries to UNION and made the data types fit to the example
UPDATE: Well, I originally wrote up a generic SQL solution for this problem, not realizing that MySQL apparently doesn't allow for it.
So if you can create a view, that may be the lightest-weight solution. (The view's defining query would be the same as the select in my original solution's with clause.)
Alternately you could create a temporary table. Maybe a little more resource-intensive if there's much data, but less likely that anyone would restrict the required permissions.
For the record, original solution was as follows:
with my_filtered as (
select *
from my_table
where a = 1 and b = 2 -- and ...
)
-- carry on with your query, using my_filtered instead of my_table
I have 2 database tables:
Table 1:
+---------+-------+-------------+
| Page | Title | Description |
+---------+-------+-------------+
| Apple | ..... | ........... |
| Orange | ..... | ........... |
| Pear | ..... | ........... |
| Grapes | ..... | ........... |
+---------+-------+-------------+
Table 2:
+----------+-------------+
| Link | Page |
+----------+-------------+
| Website1 | Apple |
| Website2 | Orange |
| Website3 | Apple |
| Website4 | Orange |
| Website5 | Apple |
| Website6 | Pear |
| Website7 | Apple |
| Website8 | Grapes |
| Website9 | Grapes |
+----------+-------------+
I want to know/return how many pages from Table 1 are referenced in Table 2 and how many times they are referenced. (I DON'T want to know how many times EACH page in Table 1 is referenced in Table 2).
So in this example:
1 page is referenced 1 time (Pear),
2 pages are referenced 2 times (Grapes and Orange) &
1 page is referenced 4 times.
What kind of SQL statement would I use to get this?
Following query should do..
SELECT COUNT(1) NoOfPages,CNT ReferencedTimes
FROM
(
SELECT T2.PAGE,COUNT(1) CNT
FROM TABLE1 T1 INNER JOIN TABLE2 T2 ON T1.PAGE = T2.PAGE
GROUP BY T2.PAGE
)T
GROUP BY CNT
I think the following statement will fit:
SELECT count(*) FROM Table2 WHERE (Table2.Page IN (SELECT Page FROM Table1));
Use This query
Select table2.page,cnt(table2.page)
from table1 inner join table2
On table1.Page=table2.Page group by table2.page
SELECT (GROUP_CONCAT(DISTINCT page)) AS Page,page_count
FROM
(SELECT table1.Page as page,COUNT(*) as page_count
FROM table1 INNER JOIN table2 ON table1.Page=table2.Page
GROUP BY table1.Page)
as T GROUP BY page_count
Hope this helps
If what you are seeking is X page was referenced N times, the below query will achieve that:
SELECT COUNT(t1.page), t2.count
FROM table1 t1
INNER JOIN (SELECT page,COUNT(*) AS count FROM table2 GROUP BY page) t2 ON t1.page=t2.page
GROUP BY t2.count
Try this query, it will make a left join and tell you how many times item is referenced in table2, if count is zero than no reference in the other table
SELECT table1.Page, count(table2.Page) as count
FROM table1
LEFT JOIN table2 ON table2.Page = table1.Page
GROUP BY table1.Page
How to delete all rows from a mysql table if values of two columns are equal
Example Table
invoice_id| item_id | name | invoiced_qty | received_qty
---------------------------------------------------------
| 1 | 1 | item1 | 3 | 2
| 2 | 2 | item2 | 5 | 5
| 3 | 1 | item3 | 4 | 3
| 4 | 2 | item4 | 2 | 2
| 5 | 1 | item5 | 5 | 5
After deleting table needs to retains
invoice_id| item_id | name | invoiced_qty | received_qty
---------------------------------------------------------
| 1 | 1 | item1 | 3 | 2
| 3 | 1 | item3 | 4 | 3
The select query which i created is
SELECT * FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
AND A.invoice_id = B.invoice_id
AND A.invoiced_qty = B.received_qty
Thanks
Why not just SQL Fiddle:
DELETE FROM table1
WHERE invoiced_qty = received_qty
Your edit does not change anything. He is the SQL Fiddle demonstrating your SELECT query. According to your sample data A.invoice_id will never equal B.invoice_id. So you will not get any results.
Try this :
DELETE FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
WHERE A.invoiced_qty = B.received_qty
You could simply wrap your select statement and select values to be deleted by id, like this:
DELETE FROM table1
WHERE item_id IN (SELECT item_id FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
AND A.invoice_id = B.invoice_id
AND A.invoiced_qty = B.received_qty)
however you should accept answer by Linger as it is more straightforward solution, mine was to indicate that if you have something selected usually you can wrap and delete.
plan_id | elementclass | table_no | ress_id | UserID | Status
1 | elementclass1 | 1 | 0 | 0006100022 | N
1 | elementclass1 | 1 | 2 | 0006100022 | N
1 | elementclass2 | 2 | 0 | 0006100021 | N
1 | elementclass4 | 3 | 0 | 0006100023 | N
in above row I am expecting as this
if row is having same elementclass,table_no but different ress_id in that condition only take that row which is non zero.If with above condition tow rows having 0 it can take any row .if both rows have non zero then also it can take any one.
Now
for rest of others it can take values with 0.We can use group by to plan_id as there may be multiple plans.
Desired result
plan_id | elementclass | table_no | ress_id | UserID | Status
1 | elementclass1 | 1 | 2 | 0006100022 | N
1 | elementclass2 | 2 | 0 | 0006100021 | N
1 | elementclass4 | 3 | 0 | 0006100023 | N
Please help.
thanks
SELECT * FROM TableName a
WHERE a.ress_id = (SELECT MAX(b.ress_id) FROM TableName b WHERE b.table_no = a.table_no)
GROUP BY a.plan_id,a.table_no
This gives you:
1 result per plai_id and table_no
each result has biggest ress_id in it
First get the maximum ress id per element class. Then select the related records. There may be duplicates. Hence group by element class and ress id.
The following statement does not precisely do what you asked for, but maybe it suffices. In case of a tie you won't get one of the records, but one of the records' plan ids, one of the records' table nos, one of the records' user ids and one of the records' statusses. So the user id may be taken from one record and the status from another when elementclass and ress_id are equal.
select plan_id, mytable.elementclass, table_no, mytable.ress_id, userid, status
from mytable
join
(
select elementclass, max(ress_id) as max_ress_id
from mytable
group by elementclass
) agg on agg.elementclass = mytable.elementclass and agg.max_ress_id = mytable.res_id
group by mytable.elementclass, mytable.ress_id;
(It is possible to write a statement to access complete records in case of ties, but this is much more complicated - at least in MySQL.)
Try this:
SELECT T1.*
FROM TableName T1 JOIN
(SELECT elementclass,table_no,MAX(ress_id) as ress_id
FROM TableName
GROUP BY elementclass,table_no
)T2 ON T1.elementclass=T2.elementclass AND T1.table_no=T2.table_no AND T1.ress_id=T2.ress_id
Explanation:
Here, we are creating a temporary table T2 with maximum of ress_id for each elementclass and table_no. Then we join this table with the original table with these 3 fields and select all records from the original table T1.
Result:
PLAN_ID ELEMENTCLASS TABLE_NO RESS_ID USERID STATUS
-------------------------------------------------------------------
1 elementclass1 1 2 0006100022 N
1 elementclass2 2 0 0006100021 N
1 elementclass4 3 0 0006100023 N
See result in SQL Fiddle.