The following is an example structure:
table `pligg`
#id #alpha #num
1 a null
2 b null
3 c null
4 a null
5 d null
6 b null
7 a null
8 e null
I'd like to update the databse like this after a single mysqli query:
table `pligg`
#id #alpha #num
1 a 1
2 b 1
3 c 1
4 a 2
5 d 1
6 b 2
7 a 3
8 e 1
What I'm trying to do is to update the column num with the number of duplicate.
I tried this query, but in vain
UPDATE pligg SET 'num' = COUNT(DISTINCT alpha) WHERE 'id'<id
This should do the trick:
UPDATE pligg a
INNER JOIN
(
SELECT a.id, a.alpha, COUNT(1) AS dup_cnt
FROM pligg a
INNER JOIN pligg b ON a.id >= b.id AND a.alpha = b.alpha
GROUP BY a.id, a.alpha
) b ON a.id = b.id
SET a.num = b.dup_cnt
SQLFiddle Demo
Related
I have a table where exists 4 entries like this.
class_type
id type
1 A
2 B
3 M
4 T
and another table where these values are foreign key.
id number id_class_type
1 10 1
2 11 1
3 12 2
4 13 1
5 14 2
6 15 3
7 16 1
8 17 3
So what i want is count(*) and group by id_class_type but with all class_type (1,2,3,4) although there is not present the id 4.
if you want only the class tha match you can use inner join
select a.class_type, count(*)
from class_type a
inner join table2 b on a.id = b.id_class_type
group by a.class_type
otherwise you can use left join
select a.class_type, count(*)
from class_type a
left join table2 b on a.id = b.id_class_type
group by a.class_type
Going off of my last question: Complex Grouping in SQL Query…
In each grouping, I'd like to grab only the row with the highest 'step' value.
This is the query we came up with in the last question:
SELECT a.*, b.*
FROM (
SELECT request_id
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
) AS sumQ
INNER JOIN tableA AS a ON sumQ.request_id = a.request_id
INNER JOIN tableB AS b ON a.request_id = b.id
That returns:
id request_id page_views step name phone
----------------------------------------------------------------
8 3 0 0 Jacob Clark 434-343-434
9 3 0 1 Jacob Clark 434-343-434
10 4 0 0 Alex Smith 222-112-2112
11 4 0 1 Alex Smith 222-112-2112
12 4 0 2 Alex Smith 222-112-2112
Which is what I wanted, however, I realized that in each group (group by request_id) I only need the row with the highest 'step' value. How can I modify my existing query to return only:
id request_id page_views step name phone
----------------------------------------------------------------
9 3 0 1 Jacob Clark 434-343-434
12 4 0 2 Alex Smith 222-112-2112
?
Then include step in the logic:
SELECT a.*, b.*
FROM (SELECT request_id, MAX(step) as maxstep
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
) sumQ INNER JOIN
tableA a
ON sumQ.request_id = a.request_id AND
sumQ.maxstep = a.step INNER JOIN
tableB b
ON a.request_id = b.id;
Have you tried setting an ORDER BY on the step field and then take the TOP record?
SELECT a.*, b.*
FROM (
SELECT TOP 1 request_id
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
ORDER BY step DESC
) AS sumQ
INNER JOIN tableA AS a ON sumQ.request_id = a.request_id
INNER JOIN tableB AS b ON a.request_id = b.id
I have 3 tables: A, B and C.
A has AID, B has AID and BID, and C has BID Value and Date.
I need to create a query that returns me AID and the first (according to date) Value from C.
WHAT I've tried:
SELECT A.AID, Value FROM A INNER JOIN B on A.AID = B.BID
INNER JOIN C ON C.BID = B.BID GROUP BY A.AID
It gives me the last Value and not the first.
Data example:
A:
AID:
1
2
3
B:
AID BID
1 1
1 2
2 3
3 4
3 5
3 6
C:
BID Value Date
1 15 1.1.1970
1 422 1.1.1992
2 945 1.1.1975
3 149 1.1.1994
3 147 1.1.2015
4 110 1.1.2004
5 142 1.1.2005
The output should be:
AID Value
1 15
2 149
3 110
If you do not have too many records with the same value and value doesn't have any commas, then the group_concat()/substring_index() trick is probably the easiest way:
select b.aid,
substring_index(group_concat(c.value order by c.date desc), ',' 1) as first_value
from c join
b
on c.bid = b.bid
group by b.aid;
Larger amounts of data require a more complicated query. Something like:
select b.aid, c.value
from c join
b
on c.bid = b.bid
where c.date = (select min(c2.date)
from c2 join
b2
on c2.bid = b2.bid
where b2.aid = b.aid
);
To restrict C to just those rows with the latest (minimum) date you need a subquery that will produce the minimum date, then use that to limit the rows from C
SELECT
A.AID
, C.Value
FROM A
INNER JOIN B ON A.AID = B.BID
INNER JOIN C ON b.bid = c.bid
INNER JOIN (
SELECT
bid
, MIN(date) AS mindate
FROM c
GROUP BY
bid
) AS m ON c.bid = m.bid
AND c.date = m.mindate
DROP TABLE IF EXISTS b;
CREATE TABLE b
(aid INT NOT NULL
,bid INT NOT NULL
,PRIMARY KEY(aid,bid)
);
INSERT INTO b VALUES
(1 ,1),
(1 ,2),
(2 ,3),
(3 ,4),
(3 ,5),
(3 ,6);
DROP TABLE IF EXISTS c;
CREATE TABLE c
(bid INT NOT NULL
,value INT NOT NULL
,date DATE
,PRIMARY KEY(bid,date)
);
INSERT INTO c VALUES
(1 ,15 ,'1970-01-01'),
(1 ,422 ,'1992-01-01'),
(2 ,945 ,'1975-01-01'),
(3 ,149 ,'1994-01-01'),
(3 ,147 ,'2015-01-01'),
(4 ,110 ,'2004-01-01'),
(5 ,142 ,'2005-01-01');
SELECT x.aid
, y.value
FROM b x
JOIN c y
ON y.bid = x.bid
JOIN
( SELECT b.aid
, MIN(c.date) min_date
FROM b
JOIN c
ON c.bid = b.bid
GROUP
BY b.aid
) z
ON z.min_date = y.date
AND z.aid = x.aid;
+-----+-------+
| aid | value |
+-----+-------+
| 1 | 15 |
| 2 | 149 |
| 3 | 110 |
+-----+-------+
I need to have first select values that are not in the second select.
select tnum,user from resp order by tnum, user
except
select test.tnum,cursa.user from cursa inner join test on test.curso = cursa.curso;
results:
select tnum,user from resp order by tnum, user;=
tnum user
1 1
1 7
1 8
1 10
2 7
select test.tnum,cursa.user from cursa inner join test on test.curso = cursa.curso;=
tnum user
1 1
1 7
1 8
1 10
2 1
2 8
3 1
3 7
3 8
3 10
4 1
4 7
4 8
4 10
I need of return tnum 2 and user 7.
This would often be solved using not exists:
select r.tnum, r.user
from resp r
where not exists (select 1
from cursa c inner join
test t
on t.curso = c.curso
where t.tnum = r.tnum and c.user = r.user
);
This has a slight difference in how it handles NULL values. If either rep.tnum or resp.user are NULL, then the row will not be removed.
If this is a possibility, then change the where clause in the subquery to:
where (t.tnum = r.tnum or (t.tnum is null and r.tnum is null) ) and
(c.user = r.user or (c.user is null and r.user is null) )
You can use a LEFT JOIN:
select tnum, user
from resp AS t1
left join (
select test.tnum, cursa.user
from cursa
inner join test
on test.curso = cursa.curso ) AS t2
ON t1.tnum = t2.tnum AND t1.user = t2.user
WHERE t2.num IS NULL AND t2.user IS NULL
order by tnum, user
The WHERE clause filters out all rows of resp that are related to rows of the derived table.
I have two tables:
builders
b_id fk_c_id
1 1
2 1
3 1
4 1
5 1
6 2
7 2
subbuilders
fk_b_id sb_id
1 2
1 3
1 4
2 5
6 7
and i want Distinct b_id which are not exist in subbuilders table and must have same fk_c_id
I create:
SELECT DISTINCT b.id FROM pms_builder_to_subbuilders bsb
LEFT JOIN pms_builders b ON b.id = bsb.sb_id WHERE b.fk_c_id = '1'
but it show Distinct records from subbuilders.
You can get the desired results with the following query:
SELECT DISTINCT b.b_id FROM builders b LEFT JOIN subbuilders sb ON sb.fk_b_id = b.b_id WHERE b.fk_c_id = '1' AND ISNULL(fk_b_id);
i think you want this query:
SELECT DISTINCT b_ID
FROM builders
WHERE b_ID NOT IN
(SELECT DISTINCT fk_b_id FROM subbuilders)
but it returns
b_ID
========
3
4
5
7
but i didn't understand your statement: must have same fk_c_id. What do you mean by that?
b_id = fk_c_id
if that's the case then there will be no rows returned because only record 1 has the same b_ID and fk_c_id but exists in table subbuilders