Find all the rows where column is letter case postgresql - sql

I have a table in postgres database where I need to find all the rows -
Between two dates where fromTo is date column.
And also only those rows where column data contains mix of lower and upper case letters. for eg: eCTiWkAohbQAlmHHAemK
I can do between two dates as shown below but confuse on second point on how to do that?
SELECT * FROM test where fromTo BETWEEN '2022-09-08' AND '2022-09-23';
Data type for fromTo column is shown below -
fromTo | timestamp without time zone | | not null | CURRENT_TIMESTAMP

You can use a regular expression to check that it is only alphabetical characters and at least one uppercase character.
select *
from foo
where data ~ '[[:upper:]]' and data ~ '^[[:alpha:]]+$';
and fromTo BETWEEN '2022-09-08' AND '2022-09-23'
The character classes will match all alphabetical characters, including those with accents.
Demonstration.
Note that this may not be able to make use of an index. If your table is large, you may need to reconsider how you're storing the data.

Related

Use subquery with multiple rows

I have been trying to work out code in SQL to clean up a data sheet (more than 200 rows and 50 columns) to add trailing zeros before the decimal point values.
I tried to apply a to_char to convert string data into a 0 padded figure, for all values less than 1
select to_char((select "1980" from imf_population where "1980" <1), '0.999')
from imf_population
However due to the subquery the to_char cannot perform a conversion on multiple rows returned from the 1980 column as there is more one record whose value is less than 1.
Any tips on how to get around this?
Your to_char must be in, not out. Once in, the outer select is not needed anymore:
select to_char("1980",'0.999') from imf_population where "1980"<1;
"1980" is a column name, right? (well, sqlite accepted create table imf_population ("1980" number); select "1980" from imf_population;, but it does not have to_char, I guess you're using oracle)
Note : Only Use Lowercase Letters, Numbers, and Underscores when
naming columns. Use Simple, Descriptive Column Names
CREATE TABLE imf_population (col varchar2(20) )
INSERT INTO imf_population (col) VALUES ('0.5289')
select to_char(col,'0.999') from imf_population where col<1;
| TO_CHAR(COL,'0.999') |
| :------------------- |
| 0.529 |
db<>fiddle here

SQLite3 Order by highest/lowest numerical value

I am trying to do a query in SQLite3 to order a column by numerical value. Instead of getting the rows ordered by the numerical value of the column, the rows are ordered alphabetically by the first digit's numerical value.
For example in the query below 110 appears before 2 because the first digit (1) is less than two. However the entire number 110 is greater than 2 and I need that to appear after 2.
sqlite> SELECT digit,text FROM test ORDER BY digit;
1|one
110|One Hundred Ten
2|TWO
3|Three
sqlite>
Is there a way to make 110 appear after 2?
It seems like digit is a stored as a string, not as a number. You need to convert it to a number to get the proper ordering. A simple approach uses:
SELECT digit, text
FROM test
ORDER BY digit + 0

How can I "dynamically" split a varchar column by specific characters?

I have a column that stores 2 values. Example below:
| Column 1 |
|some title1 =ExtractThis ; Source Title12 = ExtractThis2|
I want to remove 'ExtractThis' into one column and 'ExtractThis2' into another column. I've tried using a substring but it doesn't work as the data in column 1 is variable and therefore it doesn't always carve out my intended values. SQL below:
SELECT substring(d.Column1,13,24) FROM dbo.Table d
This returns 'Extract This' but for other columns it either takes too much or too little. Is there a function or combination of functions that will allow me to split consistently on the character? This is consistent in my column unlike my length count.
select substring(col1,CHARINDEX('=',col1)+1,CHARINDEX (';',col1)-CHARINDEX ('=',col1)-1) Val1,
substring(col1,CHARINDEX('=',col1,CHARINDEX (';',col1))+1,LEN(col1)) Val2
from #data
there is duplicate calculation that can be reduced from 5 to 3 to each line.
but I want to believe this simple optimization done by SQL SERVER.

POSTGRESQL Comparison Operators on text

I am trying to do comparison operators on my postgresql data.
I have a range of data like this
MockTable
ID | IDName | Hours | Minutes |
43 John 30 100
37 Jane 20 92
1 Don 100 22
Each of the fields on the top are labeled in the SQL server as text.
I am trying to pull information like this.
Select *
From "MockTable"
WHERE "HOURS">'25';
Thus recieving the 1st and 3rd column back. However I am not getting this results. Input?
When you compare numbers as strings, you have to think about alphabetical order. The magnitude of the number is meaningless, at this point is merely a word. So "25" is greater than "100" because the "2" comes after the "1" in an alphabetical sense.
What you need to do is either cast your "Hours" field as integer or fix that damned table because numbers in string fields is nasty.
Select * From "MockTable" WHERE CAST("Hours" as INTEGER) > 25;
Obviously, you are going to run into some difficult problems if there are records where the "Hours" field contains non-numeric characters, so you'll have to deal with that if and when it arises.
If your column names are not all-lowercase, you must specify them in double quotes and with the exact same capitalization as they are in the table:
SELECT * FROM "MockTable" WHERE "Hours" > 25;
Note this says "Hours" instead of "HOURS".
For this reason, it’s best to use all-lowercase for your column and table names. In addition, when using lowercase you won’t need to put the double-quotes around the column names unless they are a reserved word that might mean something else in that context.

PostgreSQL: order by column, with specific NON-NULL value LAST

When I discovered NULLS LAST, I kinda hoped it could be generalised to 'X LAST' in a CASE statement in the ORDER BY portion of a query.
Not so, it would seem.
I'm trying to sort a table by two columns (easy), but get the output in a specific order (easy), with one specific value of one column to appear last (got it done... ugly).
Let's say that the columns are zone and status (don't blame me for naming a column zone - I didn't name them). status only takes 2 values ('U' and 'S'), whereas zone can take any of about 100 values.
One subset of zone's values is (in pseudo-regexp) IN[0-7]Z, and those are first in the result. That's easy to do with a CASE.
zone can also take the value 'Future', which should appear LAST in the result.
In my typical kludgy-munge way, I have simply imposed a CASE value of 1000 as follows:
group by zone, status
order by (
case when zone='IN1Z' then 1
when zone='IN2Z' then 2
when zone='IN3Z' then 3
.
. -- other IN[X]Z etc
.
when zone = 'Future' then 1000
else 11 -- [number of defined cases +1]
end), zone, status
This works, but it's obviously a kludge, and I wonder if there might be one-liner doing the same.
Is there a cleaner way to achieve the same result?
Postgres allows boolean values in the ORDER BY clause, so here is your generalised 'X LAST':
ORDER BY (my_column = 'X')
The expression evaluates to boolean, resulting values sort this way:
FALSE (0)
TRUE (1)
NULL
Since we deal with non-null values, that's all we need. Here is your one-liner:
...
ORDER BY (zone = 'Future'), zone, status;
Related:
Sorting null values after all others, except special
Select query but show the result from record number 3
SQL two criteria from one group-by
I'm not familiar postgreSQL specifically, but I've worked with similar problems in MS SQL server. As far as I know, the only "nice" way to solve a problem like this is to create a separate table of zone values and assign each one a sort sequence.
For example, let's call the table ZoneSequence:
Zone | Sequence
------ | --------
IN1Z | 1
IN2Z | 2
IN3Z | 3
Future | 1000
And so on. Then you simply join ZoneSequence into your query, and sort by the Sequence column (make sure to add good indexes!).
The good thing about this method is that it's easy to maintain when new zone codes are created, as they likely will be.