I have a table tbl_entries with the following structure:
+----+------+------+------+
| id | col1 | col2 | col3 |
+----+------+------+------+
| 11 | a | b | c |
| 12 | d | e | a |
| 13 | a | b | c |
| 14 | X | e | 2 |
| 15 | a | b | c |
+----+------+------+------+
And another table tbl_reviewlist with the following structure:
+----+-------+------+------+------+
| id | entid | cola | colb | colc |
+----+-------+------+------+------+
| 1 | 12 | N | Y | Y |
| 2 | 13 | Y | N | Y |
| 3 | 14 | Y | N | N |
+----+-------+------+------+------+
Basically, tbl_reviewlist contains reviews about the entries in tbl_entries. However, for some known reason, the entries in tbl_entries are duplicated. I am extracting the unique records by the following query:
SELECT * FROM `tbl_entries` GROUP BY `col1`, `col2`, `col3`;
However, any one of the duplicate rows from tbl_entries will be returned no matter they have been reviewed or not. I want the query to prefer those rows which have been reviewed. How can I do that?
EDIT: I want to prefer rows which have been reviewed but if there are rows which have not been reviewed yet it should return those as well.
Thanks in advance!
Have you actually tried anything?
A hint: The SQL standard requires that every column in the result set of a query with a group by clause must be either
a grouping column
an aggregate function — sum(), count(), etc.,
a constant value/literal, or
an expression derived solely from the above.
Some broken implementations (and I believe MySQL is one of them) allow other columns to be included and offer their own...creative...behavior. If you think about it, group by essentially says to do the following:
Order this table by the grouping expressions
Partition it into subsets based on the group by sequence
Collapse each such partition into a single row computing the aggregate expressions as you go.
Once you've done that, what does it mean to ask for something that isn't uniform across the collapsed group partition?
If you have a table foo containing columns A, B, C, D and E and say something like
select A,B,C,D,E from foo group by A,B,C
per the standard, you should get a compile error. Deviant implementations [usually] treat this sort of query as the [rough] equivalent of
select *
from foo t
join ( select A,B,C
from foo
group by A,B,C
) x on x.A = t.A
and x.B = t.B
and x.C = t.C
But I wouldn't necessarily count on that without review the documentation for the specific implementation that your are using.
If you want to find just reviewed entries, then something like this:
select *
from tbl_entries t
where exists ( select *
from tbl_reviewlist x
where x.entid = t.id
)
will do you. If, however, you want to find reviewed entries that are duplicated on col1, col2 and col3 then something like this should do you:
select *
from tbl_entries t
join ( select col1,col2,col3
from tbl_entries x
group by col1,col2,col3
having count(*) > 1
) d on d.col1 = t.col1
and d.col2 = t.col2
and d.col3 = t.col3
where exists ( select *
from tbl_reviewlist x
where x.entid = t.id
)
Since your problem statement is rather unclear, another take might be something along these lines:
select t.col1 ,
t.col2 ,
t.col3 ,
t.duplicate_count ,
coalesce(x.review_count,0) as review_count
from ( select col1 ,
col2 ,
col3 ,
count(*) as duplicate_count
from tbl_entries
group by col1 ,
col2 ,
col3
) t
left join ( select cola, colb, colc , count(*) as review_count
from tbl_reviewList
group by cola, colb, colc
having count(*) > 1
) x on x.cola = t.col1
and x.colb = t.col2
and x.colc = t.col3
order by sign(coalesce(x.review_count,0)) desc ,
t.col1 ,
t.col2 ,
t.col3
This query
summarizes the entries table, developing a count of how many time seach col1/2/3 combination exists.
summarizes the review table, developing a count of reviews for each cola/b/c combination
joins them together matching cols a:1, b:2 c:3
orders them
preferring reviewed items to non-reviewed items by placing them first,
then by the col1/2/3 values.
I think there's a way with less repetition, but this should be a start:
select
tbl_entries.ID,
col1,
col2,
col3,
cola, -- ... you get the idea ...
from (
select coalesce(min(entid), min(tbl_entries.ID)) as favID
from tbl_entries left join tbl_reviewlist on entid = tbl_entries.ID
group by col1, col2, col3
) as A join tbl_entries on tbl_entries.ID = favID
left join tbl_reviewlist on entid = tbl_entries.ID
Basically you distill the desired output to a list of core ID's and then re-map back to the data...
SELECT e.col1, e.col2, e.col3,
COALESCE(MIN(r.entid), MIN(e.id)) AS id
FROM tbl_entries AS e
LEFT JOIN tbl_reviewlist AS r
ON r.entid = e.id
GROUP BY e.col1, e.col2, e.col3 ;
Tested at SQL-Fiddle
Related
table one
+----------------------+
|column A | Column B|
| 2 | 4 |
| 3 | 5 |
| 1 | 2 |
| 1 | 2 |
| 8 | 7 |
+----------------------+
Output
+-------+
|1 | 2 |
|1 | 2 |
+-------+
i want to print only the above output without COUNT, and any duplicate record example? please help
how about below where cluase
select * from t where columnA=1 and columnB=2
or
select columnA,columnB from t
group by columnA,columnB
having count(*)>1
or you can use exists
select t1.* from t t1 where exists
(select 1 from t t2 where t2.columnA=t1.columnA
and t2.columnB=t1.columnB group by columnA,columnB
having count(*)>1
)
You possibly want only those rows which are duplicate. If you don't have Window Functions available in your MySQL version, you can do the following:
SELECT
t.*
FROM your_table AS t
JOIN (SELECT columnA, columnB
FROM your_table
GROUP BY columnA, columnB
HAVING COUNT(*) > 1) AS dt
ON dt.columnA = t.columnA AND dt.columnB = t.columnB
Details: In a Derived table, we get all those combination of columnA and columnB which have more than one row(s) (HAVING COUNT(*) > 1).
Now, we simply join this result-set back to the main table, to get those rows only.
Note: This approach would not be needed if you want to fetch only these two columns. A simple Group By with Having would suffice, as suggested in other answer(s). However, if you have more columns in the table, and you will need to fetch all of them, and not just the columns (used to determine duplicates); you will need to use this approach.
You can use in operator with a grouped subquery as :
select *
from tab
where ( columnA, columnB) in
(
select columnA, count(columnA)
from tab
group by columnA
);
or use a self-join as :
select t1.columnA, t1.columnB
from tab t1
join
(
select columnA, count(columnA) as columnB
from tab
group by columnA
) t2
on ( t1.columnA = t2.columnA and t1.columnB = t2.columnB );
Rextester Demo
I would use EXISTS, if the table has primary column :
SELECT t.*
FROM table t
WHERE EXISTS (SELECT 1 FROM table t1 WHERE t1.col1 = t.col1 AND t1.col2 = t.col2 AND t1.pk <> t.pk);
How can I count the occurrence of the field/column in SQL?
Example dataset:
A
A
A
A
B
B
C
I want:
A | 4
A | 4
A | 4
A | 4
B | 2
B | 2
C | 1
Is there anyway to do it without using GROUP BY? So far all answer I get my query retuns the following:
A | 4
B | 2
C | 1
select value, count(*) from table group by value
Use HAVING to further reduce the results, e.g. only values that occur more than 3 times:
select value, count(*) from table group by value having count(*) > 3
You could use a nested sub-select for this desired result set.
If the example table name is my_table and the column called col1:
select col1,
(select count(*) from my_table where col1 = t.col1) as Count
from my_table t;
Or if you want to remove the duplicates, use the distinct statement. It removes the duplicates of your result set.
select distinct col1,
(select count(*) from my_table where col1 = t.col1) as Count
from my_table t;
I have a table like this in MYSQL:
ID | NAME | VALUE |
----------------------------
1 | Bob | 1 |
2 | Bob | 2 |
3 | Jack | 5 |
4 | Jack | 8 |
5 | Jack | 10 |
and I'm trying to update the VALUE column to the highest value of rows with same NAME. So the result should be:
ID | NAME | VALUE |
----------------------------
1 | Bob | 2 |
2 | Bob | 2 |
3 | Jack | 10 |
4 | Jack | 10 |
5 | Jack | 10 |
I managed to get the max value like this:
SELECT MAX(Value) max FROM `table` GROUP BY Name having count(*) >1 AND MAX(Value) != MIN(Value)
But can't figure out how to put it in my update
Update table set Value = (SELECT MAX(Value) max FROM `table` GROUP BY Name having count(*) >1 AND MAX(Value) != MIN(Value))
Doesn't work. I'd appreciate any help.
This is easier than other answers are making it.
UPDATE MyTable AS t1 INNER JOIN MyTable AS t2 USING (Name)
SET Value = GREATEST(t1.Value, t2.Value);
You don't have to find the largest value. You just have to join each row to the set of rows with the same name, and set the Value to the greater Value of the two joined rows. This is a no-op on some rows, but it will apply to every row in turn.
http://sqlfiddle.com/#!9/f79a3/1
UPDATE t1
INNER JOIN (SELECT name, MAX(`value`) max_value
FROM t1 GROUP BY name) t2
ON t1.name = t2.name
SET t1.value = t2.max_value;
Create a temporary table consisting of ID NAME and MAX VALUE as follows:
CREATE TEMP TABLE TABLE1 AS
(SELECT NAME,MAX(Value) value FROM `table` GROUP BY Name having count(*) >1
AND MAX(Value) != MIN(Value)
);
Use this temporary table to do your update as follows:
UPDATE
Table_A
SET
Table_A.value = Table_B.value
FROM
`table` AS Table_A
INNER JOIN TABLE1 AS Table_B
ON Table_A.NAME = Table_B.NAME
Also this code is somewhat of an approximation as i am not familiar with mysql but i am familiar with sql.
Let me know if this doesn't help.
Simple left join would do the trick.
Try this out and let me know in case of any queries.
select a.id,a.name,b.value
from
table a
left join
(select name,max(value) as value from table group by name) b
on a.name=b.name;
You may use this query. The table is joined with a subquery (table t2) that contains the results you want to update your table with:
UPDATE `table` t1,
(SELECT Name, MAX(Value) maxv, MIN(Value) minv
FROM `table`
GROUP BY Name
HAVING COUNT(*)>1 AND maxv != minv) t2
SET t1.Value = t2.maxv
WHERE t1.Name = t2.Name;
If you want to know how will the values be updated, you can first run an equivalent SELECT query:
SELECT t1.*, t2.maxv
FROM `table` t1,
(SELECT Name, MAX(Value) maxv, MIN(Value) minv
FROM `table`
GROUP BY Name
HAVING COUNT(*)>1 AND maxv != minv) t2
WHERE t1.Name = t2.Name;
This query will display all the fields of table, followed by the new value maxv. You can check the current value and the new value, and if it looks fine, you may run the UPDATE query.
I have a table with two sets of integer values. Using MySQL I want to display all of the rows that correspond to unique entries in the second column. Basically I can have duplicate A values, but only unique B values. If there are duplicates for a value in B, remove all the results with that value. If I use DISTINCT I will still get one of those duplicates which I do not want. I also want to avoid using COUNT(). Here's an example:
|_A____B_|
| 1 2 |
| 1 3 |
| 2 2 |
| 2 4 |
| 1 4 |
| 5 5 |
Will have the following Results (1,3), (5,5). Any value in B that has a duplicate is removed.
Try this
SELECT * FROM TEMP WHERE B IN (
SELECT B FROM TEMP GROUP BY B Having COUNT(B)=1
);
I know you want to avoid using COUNT() but this is the quick solution.
working fiddle here - http://sqlfiddle.com/#!9/29d16/8
Tested and works! you need atleast count(*) to count the values
select * from test where B in (
select B from test group by B having count(*)<2
)
I don't know why you want to avoid using count(), because that's what would do the trick as follows:
Let's say your table is named "mytable"
SELECT t1.A, t1.B
FROM mytable t1
JOIN (
SELECT B, count(*) AS B_INSTANCES
FROM mytable
GROUP BY B
HAVING count(*) = 1
) t2 ON t2.B = t1.B
ORDER BY t1.A, t1.B
Is it possible to select the next lower number from a table without using limit.
Eg: If my table had 10, 3, 2 , 1 I'm trying to select * from table where col > 10.
The result I'm expecting is 3. I know I can use limit 1, but can it be done without that?
Try
SELECT MAX(no) no
FROM table1
WHERE no < 10
Output:
| NO |
------
| 3 |
SQLFiddle
Try this query
SELECT
*
FROM
(SELECT
#rid:=#rid+1 as rId,
a.*
FROM
tbl a
JOIN
(SELECT #rid:=0) b
ORDER BY
id DESC)tmp
WHERE rId=2;
SQL FIDDLE:
| RID | ID | TYPE | DETAILS |
------------------------------------
| 2 | 28 | Twitter | #sqlfiddle5 |
Another approach
select a.* from supportContacts a inner join
(select max(id) as id
from supportContacts
where
id in (select id from supportContacts where id not in
(select max(id) from supportContacts)))b
on a.id=b.id
SQL FIDDLE:
| ID | TYPE | DETAILS |
------------------------------
| 28 | Twitter | #sqlfiddle5 |
Alternatively, this query will always get the second highest number based on the inner where clause.
SELECT *
FROM
(
SELECT t.col,
(
SELECT COUNT(distinct t2.col)
FROM tableName t2
WHERE t2.col >= t.col
) as rank
FROM tablename t
WHERE col <= 10
) xx
WHERE rank = 2 -- <<== means second highest
SQLFiddle Demo
SQLFiddle Demo (supports duplicate values)
If you want to get next lower number from table
you can get it with this query:
SELECT distinct col FROM table1 a
WHERE 2 = (SELECT count(DISTINCT(b.col)) FROM table1 b WHERE a.col >= b.col);
later again if you want to get third lower number you can just pass 3 in place of 2 in where clause
again if you want to get second higher number, just change the condition of where clause in inner query with
a.col <= b.col