SQL Get last rows of different enum values - mysql

I do have a table with one "type"-column, this column is a enum with eight possibilities. I now want to query the last row of each enum value - so if I'm looking for four of the eight possible values, I want four rows with each one of the enums.
Any ideas?
Edit examples:
following enum: type=("example1","ex2","ex3")
Each row has a type and a timestamp
I'd like to have the last timestamp of every type.
Sample Data:
example 1 - 7:13,
ex2 - 8:14,
example 1 - 9:17,
ex3 - 6:13
Wished Result:
example 1 - 9:17,
ex2 - 8:14
Dialect is MySQL. Thanks!

If your table MyTable has an "enum" column named EnumColumn, and you want last row for each value in a list of given enum values (Foo, Bar, and Baz), where "last" is defined by a DateColumn, and you're using a database that supports windowing functions (e.g. MS SQL Server, Oracle, PostgreSQL), you can do it like this:
SELECT Column1, EnumColumn, Column3, DateColumn, Column5
FROM ( SELECT Column1, EnumColumn, Column3, DateColumn, Column5
, ROW_NUMBER() OVER ( PARTITION BY EnumColumn
ORDER BY DateColumn DESC ) AS ROW_NUM
FROM MyTable
WHERE EnumColumn IN ('Foo', 'Bar', 'Baz')
) x
WHERE ROW_NUM = 1

Related

Order by first non-null result that comes from two different columns

I want to browse through all values of two columns in a table:
if the value in column 1 is not null, select it, otherwise select the value in column 2 instead.
then sort the final result in alphabetical ascending order, wherever column its values came from.
I tried the following query but it doesn't work and I'm not even sure it is supposed to do what I want to do.
SELECT *
FROM table
ORDER BY (CASE WHEN col1 IS NOT NULL THEN 1 ELSE 2 END ),
col1 DESC,
col2 DESC)
Besides the fact that it doesn't work (nothing outputted), it seems to sort the values of each column separately while I want to sort the final set of values retrieved, regardless of the column they are from.
Thank you for your help.
If you want to fix it with the CASE expression, it'd look like the following:
SELECT *,
CASE WHEN col1 IS NOT NULL
THEN col1
ELSE col2
END AS col
FROM table
ORDER BY col
Although a nice option is using the COALESCE function. It returns the first non-null value in the list of arguments.
SELECT *, COALESCE(col1, col2) AS col
FROM table
ORDER BY col

How to Create text string in MySQL against all records in a view

I'm looking to see if I can create a view where I can create a third column that always shows a text string made up of the Current Year-Current WeekNo so a sample would be 2021-26 or 2021-23.
The whole point is that I effectively need to timestamp set columns against the year-week so the view would be
Column1 - Type
Column2 - Value
Column3 - year-week
An event then copies this info to another table where the I have an accurate time stamp in the format year-week.
MySqls own timestamp is not relevant for this task and I can get the single result using (select WEEK(CURDATE(),0)) as 'Week_No', (SELECT YEAR(CURDATE())) as 'Year'
Any input would be good. Thanks
You could try adding something like this to the field list:
concat(year(curdate()), '-', week(curdate(), 1)) as 'year_week'
week has various options for how to show/calculate the week number.
dual is a dummy table name in situations where no tables are referenced
e.g.:
select
'value' as value,
'type' as type,
concat(year(curdate()), '-', week(curdate(), 1)) as 'year_week'
from dual
Demo: http://sqlfiddle.com/#!9/9eecb/227666

Generate MQsql query to get records

I am having the following table say "A"
"column1" "column2"
1 arafath#gmail.com
2 ram#gmail.com;arafath#gmail.com
3 tom#gmail.com
I want to get the records with the following condition.
Condition1:
If the column value exist in the any of the row, it will retrieve the matched rows
Condition2:
If the column value doesn't match with any of the row, it wants to retrieve all the rows
Eg: column2 = "ram#gmail.com"
Output should be "row 2"
Eg: column2 = "arafath#gmail.com"
Output should be "row 1, row 2"
Eg: column2 = "xxx#gmail.com" (Unmatched column)
Output should be all the rows (row 1, row 2, row 3)
Please help me out to solve the problem.
Thanks in advance.
Please try the below one.
SELECT col1, col2
FROM yourTable
where ( not exists (Select col2
FROM yourTable where col2 like 'xxx#gmail.com')
or col2 like 'xxx#gmail.com');
We can try using a union here:
SELECT col1, col2
FROM yourTable
WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]'
UNION ALL
SELECT col1, col2
FROM yourTable
WHERE col2 NOT REGEXP '[[:<:]]ram#gmail.com[[:>:]]' AND
NOT EXISTS (SELECT 1 FROM yourTable WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]');
Demo
The above strategy is that the first half of the union returns the matching record, if it exists. The second half of the union then returns all other records, but only if on match were found in the first half of the union. If a match were found, then the WHERE clause in the second half of the union would fail, and would return nothing.
Also, please note that storing comma separated (or semicolon separated) data in your MySQL tables is generally bad practice. I had to use REGEXP to get around this problem, but ideally if each email had a separate row, we would only need to use = equality.

mysql query sort database

Hello I have a table with 4 column in the column 4 the value come from a list box already pre establish by me , let say column 4 is populate by value a,b,c,d,e,f,g,h,i,j.
presently I can sort them in alpha order and get that on a PHP page .
I will like to be able to get on a page just d,e and f
how can I achieve that
thank you all
SELECT * FROM mytable WHERE mycolumn4 IN ('d','e','f')
You can just do:
SELECT column4
FROM TABLE
WHERE column4 IN ('d','e','f')
ORDER BY column4 ASC;
or if you know you want the elents with letters "bigger" than 'd' but don't know how many they are, you can do:
SELECT column4
FROM TABLE
WHERE column4 >= 'd'
ORDER BY column4 ASC;

PostgreSQL equivalent for MySQL GROUP BY

I need to find duplicates in a table. In MySQL I simply write:
SELECT *,count(id) count FROM `MY_TABLE`
GROUP BY SOME_COLUMN ORDER BY count DESC
This query nicely:
Finds duplicates based on SOME_COLUMN, giving its repetition count.
Sorts in desc order of repetition, which is useful to quickly scan major dups.
Chooses a random value for all remaining columns, giving me an idea of values in those columns.
Similar query in Postgres greets me with an error:
column "MY_TABLE.SOME_COLUMN" must appear in the GROUP BY clause or be
used in an aggregate function
What is the Postgres equivalent of this query?
PS: I know that MySQL behaviour deviates from SQL standards.
Back-ticks are a non-standard MySQL thing. Use the canonical double quotes to quote identifiers (possible in MySQL, too). That is, if your table in fact is named "MY_TABLE" (all upper case). If you (more wisely) named it my_table (all lower case), then you can remove the double quotes or use lower case.
Also, I use ct instead of count as alias, because it is bad practice to use function names as identifiers.
Simple case
This would work with PostgreSQL 9.1:
SELECT *, count(id) ct
FROM my_table
GROUP BY primary_key_column(s)
ORDER BY ct DESC;
It requires primary key column(s) in the GROUP BY clause. The results are identical to a MySQL query, but ct would always be 1 (or 0 if id IS NULL) - useless to find duplicates.
Group by other than primary key columns
If you want to group by other column(s), things get more complicated. This query mimics the behavior of your MySQL query - and you can use *.
SELECT DISTINCT ON (1, some_column)
count(*) OVER (PARTITION BY some_column) AS ct
,*
FROM my_table
ORDER BY 1 DESC, some_column, id, col1;
This works because DISTINCT ON (PostgreSQL specific), like DISTINCT (SQL-Standard), are applied after the window function count(*) OVER (...). Window functions (with the OVER clause) require PostgreSQL 8.4 or later and are not available in MySQL.
Works with any table, regardless of primary or unique constraints.
The 1 in DISTINCT ON and ORDER BY is just shorthand to refer to the ordinal number of the item in the SELECT list.
SQL Fiddle to demonstrate both side by side.
More details in this closely related answer:
Select first row in each GROUP BY group?
count(*) vs. count(id)
If you are looking for duplicates, you are better off with count(*) than with count(id). There is a subtle difference if id can be NULL, because NULL values are not counted - while count(*) counts all rows. If id is defined NOT NULL, results are the same, but count(*) is generally more appropriate (and slightly faster, too).
Here's another approach, uses DISTINCT ON:
select
distinct on(ct, some_column)
*,
count(id) over(PARTITION BY some_column) as ct
from my_table x
order by ct desc, some_column, id
Data source:
CREATE TABLE my_table (some_column int, id int, col1 int);
INSERT INTO my_table VALUES
(1, 3, 4)
,(2, 4, 1)
,(2, 5, 1)
,(3, 6, 4)
,(3, 7, 3)
,(4, 8, 3)
,(4, 9, 4)
,(5, 10, 1)
,(5, 11, 2)
,(5, 11, 3);
Output:
SOME_COLUMN ID COL1 CT
5 10 1 3
2 4 1 2
3 6 4 2
4 8 3 2
1 3 4 1
Live test: http://www.sqlfiddle.com/#!1/e2509/1
DISTINCT ON documentation: http://www.postgresonline.com/journal/archives/4-Using-Distinct-ON-to-return-newest-order-for-each-customer.html
mysql allows group by to omit non-aggregated selected columns from the group by list, which it executes by returning the first row found for each unique combination of grouped by columns. This is non-standard SQL behaviour.
postgres on the other hand is SQL standard compliant.
There is no equivalent query in postgres.
Here is a self-joined CTE, which allows you to use select *. key0 is the intended unique key, {key1,key2} are the additional key elements needed to address the currently non-unique rows. Use at your own risk, YMMV.
WITH zcte AS (
SELECT DISTINCT tt.key0
, MIN(tt.key1) AS key1
, MIN(tt.key2) AS key2
, COUNT(*) AS cnt
FROM ztable tt
GROUP BY tt.key0
HAVING COUNT(*) > 1
)
SELECT zt.*
, zc.cnt AS cnt
FROM ztable zt
JOIN zcte zc ON zc.key0 = zt.key0 AND zc.key1 = zt.key1 AND zc.key2 = zt.key2
ORDER BY zt.key0, zt.key1,zt.key2
;
BTW: to get the intended behaviour for the OP, the HAVING COUNT(*) > 1 clause should be omitted.