I have a tablename contacts which has columns [ "id","name","age" ].I need to get all the contacts order by name in ascending order.I wrote the following query for it:
Select * from contacts order by name collate nocase asc;
The results I get from the above above query are following:
1. 11 | #ax Nene | 21
1. 21 | 123 Ray | 22
1. 33 | maxy Wel | 25
1. 41 | Max Vele | 23
1. 53 | Nam sing | 25
The above ordering is fine but I want names starting with special characters [#,$ or any other non-alphabet] to be at the bottom in the results rather than at top.What should I modify in my query to achieve the desired results.
NOTE: I am using sqlite.
You have to prepend some character like ~ (which is sorted after letters) to any such string.
When you do this only in the ORDER BY clause, it affects only the sorting and not the returned values:
SELECT *
FROM contacts
ORDER BY CASE WHEN name GLOB '[A-Za-z]*'
THEN name
ELSE '~' || name
END COLLATE NOCASE;
(COLLATE NOCASE makes the sorting case-insensitive.)
Related
I have a table with a large amount of data; moving forward, I would like to enforce uniqueness for a given column in this table. However, the table contains a large amount of rows where that column is non-unique. I am not able to delete or alter these rows.
Is it possible to enforce uniqueness over a given date range, or since a specific date, or based on the value of another column (or something else like that) in MariaDB?
You can create a UNIQUE index on multiple columns, where one column is nullable. MariaDB will see each column with NULL values as a different value regarding the UNIQUE index, even if the other column values of the UNIQUE index are the same. Check the MariaDB documentation Getting Started with Indexes - Unique Index:
The fact that a UNIQUE constraint can be NULL is often overlooked. In SQL any NULL is never equal to anything, not even to another NULL. Consequently, a UNIQUE constraint will not prevent one from storing duplicate rows if they contain null values:
CREATE TABLE t1 (a INT NOT NULL, b INT, UNIQUE (a,b));
INSERT INTO t1 values (3,NULL), (3, NULL);
SELECT * FROM t1;
+---+------+
| a | b |
+---+------+
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | NULL |
| 3 | NULL |
+---+------+
You can create such a UNIQUE index on the date column you already have and a new column which indicates if the date value should be unique or not:
CREATE TABLE Foobar(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
createdAt DATE NOT NULL,
dateUniqueMarker BIT NULL DEFAULT 0,
UNIQUE KEY uq_createdAt(createdAt, dateUniqueMarker)
);
INSERT INTO Foobar(createdAt) VALUES ('2021-11-04'),('2021-11-05'),('2021-11-06');
SELECT * FROM Foobar;
+----+------------+------------------------------------+
| id | createdAt | dateUniqueMarker |
+----+------------+------------------------------------+
| 1 | 2021-11-04 | 0x00 |
| 2 | 2021-11-05 | 0x00 |
| 3 | 2021-11-06 | 0x00 |
+----+------------+------------------------------------+
INSERT INTO Foobar(createdAt) VALUES ('2021-11-05');
ERROR 1062 (23000): Duplicate entry '2021-11-05-\x00' for key 'Foobar.uq_createdAt'
UPDATE Foobar SET dateUniqueMarker = NULL WHERE createdAt = '2021-11-05';
INSERT INTO Foobar(createdAt, dateUniqueMarker) VALUES ('2021-11-05', NULL);
SELECT * FROM Foobar;
+----+------------+------------------------------------+
| id | createdAt | dateUniqueMarker |
+----+------------+------------------------------------+
| 1 | 2021-11-04 | 0x00 |
| 2 | 2021-11-05 | NULL |
| 5 | 2021-11-05 | NULL |
| 3 | 2021-11-06 | 0x00 |
+----+------------+------------------------------------+
Without any data example and scenario illustration, it's hard to know. If you can update your question with those information, please do.
"Is it possible to enforce uniqueness over a given date range, or since a specific date, or based on the value of another column (or something else like that) in MariaDB?"
If by "enforce" you mean to create a new column then populate it with unique identifier, then yes it is possible. If what you really mean is to generate a unique value based on other column, that's also possible. Question is, how unique do you want it to be?
Is it like this unique?
column1
column2
column3
unique_val
2021-02-02
ABC
DEF
1
2021-02-02
CBD
FEA
1
2021-02-03
BED
GER
2
2021-02-04
ART
TOY
3
2021-02-04
ZSE
KSL
3
Whereby if it's the same date (on column1), it should have the same unique value regardless of column2 & column3 data.
Or like this?
column1
column2
column3
unique_val
2021-02-02
ABC
DEF
1
2021-02-02
CBD
FEA
2
2021-02-03
BED
GER
3
2021-02-04
ART
TOY
4
2021-02-04
ZSE
KSL
5
Taking all (or certain) columns to consider the unique value.
Both of the scenario above can be achieved in query without the need to alter the table, adding and populate a new column but of course, the latter is also possible.
I have a table with emojis like this :
MariaDB> SELECT HEX(value), value FROM `emojis`;
+----------------------------+-------+
| HEX(value) | value |
+----------------------------+-------+
| F09F9AA9 | 🚩 |
| F09F8FB4 | 🏴 |
| E29C94EFB88F | ✔️ |
| F09F9AA9 | 🏴 |
| F09F8FB4 | 🧛♀️ |
| F09FA79BE2808DE29980EFB88F | 💋 |
+----------------------------+-------+
But when I add a group by, some values are not returned :
MariaDB> SELECT value, HEX(value) FROM `emojis` GROUP BY value;
+-------+----------------------------+
| value | HEX(value) |
+-------+----------------------------+
| ✔️ | E29C94EFB88F |
| 🧛♀️ | F09F9AA9 |
| 🚩 | F09FA79BE2808DE29980EFB88F |
+-------+----------------------------+
The black flag and the kiss are missing. It looks like MariaDB can not do a group by with UTF8 MB4 characters.
My column type is : varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL;
I tried with Mariadb 10.1 and 10.5, and got the same result.
Is this a bug or am I missing something ?
HEX is not an aggregate function, so you cannot use as one with GROUP BY. If you wish to get the different emojis and the respective hex-values use DISTINCT.
You should (see Character Collating Weights) store the emojis as utf8mb4_bin instead utf8mb4_unicode_ci. The reason for this is how the character's collating weight is determined. See handling of comparision of characters with WEIGTH_STRING-function.
SELECT DISTINCT value, HEX(value)
FROM emojis;
See db-fiddle
The query like this should not be used:
SELECT value
FROM emojis
GROUP BY value;
The GROUP BY should be used only when you mix normal columns with aggregate functions. As said, use DISTINCT instead.
Thanks to your answers I understand what difference it makes to use utf8mb4_bin or utf8mb4_unicode_ci when using DISTINCT or GROUP BY and other functions comparing strings.
But in my case I could not change the encoding of my column, but I learned that collations could be specified in request, like this :
SELECT id, value
FROM `emojis`
GROUP BY value COLLATE utf8mb4_bin;
Warning this is not working if sql_mode is ONLY_FULL_GROUP_BY.
The collation of Emoji changed at some point in the history of Unicode. The older collation utf8mb4_unicode_ci (version 4.0) treated them as equal. Newer collation utf8mb4_unicode_520 (version 5.20) treated them as unequal.
GROUP BY and ORDER BY and < depend on collation.
Env: Oracle APEX v5.1 with Oracle 12c Release 2
Firstly, I have created an Interactive Grid that isn't based off an underlying table as I will process this manually using PL/SQL.
I have been using the following as a guide:
https://apex.oracle.com/pls/apex/germancommunities/apexcommunity/tipp/6361/index-en.html
I basically have the following query:
select
level as id,
level as grid_row,
null as product,
null as product_item
from dual connect by level <= 1
Concentrating on just the product and product_item columns where the product_item column will be a readonly column and only the product number can be entered, I would like to achieve the following:
Product Product Item
---------- -------------
123456 123456-1
123456 123456-2
556677 556677-1
654321 654321-1
654321 654321-2
654321 654321-3
123456 123456-3
From the above, as the user types in the Product and then tabs out of the field, I would like a DA to fire that will add the sequence of "-1" to the end of that product number. Then is the user then adds another row within the IG and enters the same product number, I then want it to append "-2" to the end of it.
Only when the product changes number, I need the sequence to reset to "-1" for that new product as per 556677 and so forth.
Other scenarios that should also be taken into consideration are as follows:
From above IG, the user entered 123456 again but this should calculate that the next sequence for 123456 is "-3"
The same needs to be catered for, when a Product is removed from the IG but to always look at the max sequence number for that product.
I was thinking of possibly using APEX_COLLECTIONS as a means of storing what is currently in the grid, since no changes have been committed to the database.
Assuming you have a collection of product values (in this case, I am using the built-in SYS.ODCINUMBERLIST which is a VARRAY data type) then the SQL for your output would be:
SELECT id,
id AS grid_row,
product,
product || '-' || ROW_NUMBER() OVER ( PARTITION BY product ORDER BY id )
AS product_item
FROM (
SELECT ROWNUM AS id,
COLUMN_VALUE AS product
FROM TABLE(
SYS.ODCINUMBERLIST(
123456,
123456,
556677,
654321,
654321,
654321,
123456
)
)
)
ORDER BY id
Output:
ID | GRID_ROW | PRODUCT | PRODUCT_ITEM
-: | -------: | ------: | :-----------
1 | 1 | 123456 | 123456-1
2 | 2 | 123456 | 123456-2
3 | 3 | 556677 | 556677-1
4 | 4 | 654321 | 654321-1
5 | 5 | 654321 | 654321-2
6 | 6 | 654321 | 654321-3
7 | 7 | 123456 | 123456-3
db<>fiddle here
As you mentioned, the data you enter is not saved into the DB whilst you are inserting your products, so it is not in fact stored anywhere.
So you cannot go check if that value already exists and enter a -2 or other.
Some things to consider would be to maybe save the values into a temp table so you can then have a function go check how many product_item like 123456-% are in there and use that number +1 as your new product_item.
Or you could go the even harder way and do it all with javascript. For this you will need to somehow get all records in the IG, go through them all and see how many occurences of 123456 you have and then insert 123456-(no of occurences + 1).
I have the following table:
date | id
-----------|------
unixtime_1 | 2
unixtime_1 | 7
unixtime_1 | 9
unixtime_1 | 24
unixtime_1 | 29
unixtime_1 | 21
unixtime_2 | 8
So far I get the results from such a table doing so:
SELECT date, id FROM table ORDER BY date DESC, id ASC
and I get
unixtime_1 | 2
unixtime_1 | 7
unixtime_1 | 9
unixtime_1 | 21
unixtime_1 | 24
unixtime_1 | 29
unixtime_2 | 8
I was wondering whether I could LIMIT the result so that in the range id=1-10 id=11-20 and id=21-30 I could get in the result only the record with the higher id.
So:
unixtime_1 | 9
unixtime_1 | 29
Since for id range=11-20 there isn't any record, it should be skip the range.
The range now are 1-10, 11-20, 21-30 but are custom ranges set by me according to the user request so I should be able to change them.
Is that possible via query?
Thank you
Your latest requirement should be possible to achieve merely by grouping by the date and (id - 1) / <some_number>, where in your example <some_number> would be 10.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT date, (id - 1) / 10 AS id_grp, MAX(id) AS max_id
FROM yourTable
GROUP BY date, (id - 1) / 10
) t2
ON t1.date = t2.date AND t1.id = t2.max_id
ORDER BY
t1.date, t1.id;
You may choose any range you want 1 - num by simply replacing 10 in my query with the end of the range.
If i did understand correctly and if your range is id=1-3
you could simply do:
SELECT id, date FROM table WHERE id>=1 AND id<=3 ORDER by id DESC, date DESC limit 1;
this will give you only 1 record with the highest id in the range id=1-3.
you can store it and perform another query for another range and combine them later
Try this:
SELECT date, MAX(ID) FROM table GROUP BY date
I have a table with this structure:
id | IDs | Name | Type
1 | 10 | A | 1
2 | 11 | B | 1
3 | 12 | C | 2
4 | 13 | D | 3
except id nothing else is a FOREIGN or PRIMARY KEY. I want to select a row based on it's column values that are not PRIMARY KEY. I have tried the following syntax but it yields no results.
SELECT * FROM MyTable WHERE Name = 'A', Type = 1;
what am I doing wrong? What is exactly returned by a SELECT statement? I'm totally new to Data Base and I'm currently experimenting and trying to learn it. so far my search has not yield any results regarding this case.
Use and to add multiple conditions to your query
SELECT *
FROM MyTable
WHERE Name = 'A'
AND Type = 1;