Syntax to manually insert a UUID value in Postgres - postgresql

I have a table that was created as such:
CREATE TABLE IF NOT EXISTS DIM_Jour (
jour_id uuid NOT NULL,
AAAA int,
MM int,
JJ int,
Jour_Semaine int,
Num_Semaine int,
PRIMARY KEY (jour_id)
);
I'm trying to manually insert some value for testing purposes. I know that eventually I would need to use a UUID generator.
INSERT INTO DIM_Jour (jour_id, AAAA, MM, JJ, Jour_Semaine, Num_Semaine) VALUES (
292a485f-a56a-4938-8f1a-bbbbbbbbbbb1,
2020,
11,
19,
4,
47
);
I get this error (or similar)
ERROR: syntax error at or near "a485f"
LINE 3: 292a485f-a56a-4938-8f1a-bbbbbbbbbbb1,
^
I've tried the different formats mentioned in the Postgres documentation, but it seems like it doesn't except any format. Is it a stupid syntax issue or am I missing something here? What is the correct syntax?

You could pass it as a string literal and have the database implicitly convert it to a UUID:
INSERT INTO DIM_Jour (jour_id, AAAA, MM, JJ, Jour_Semaine, Num_Semaine) VALUES (
'292a485f-a56a-4938-8f1a-bbbbbbbbbbb1',
2020,
11,
19,
4,
47
);
But it's probably a good practice to be explicit about it and perform the cast yourself
INSERT INTO DIM_Jour (jour_id, AAAA, MM, JJ, Jour_Semaine, Num_Semaine) VALUES (
'292a485f-a56a-4938-8f1a-bbbbbbbbbbb1'::UUID,
2020,
11,
19,
4,
47
);

You should use UUID generator and install UUID extension. PostgreSQL requires valid UUIDs conforming to RFC 4122. Random strings are not valid UUIDs.
Also, as it is mentioned below, you should pass your UUIDs as quoted strings.

Related

How to format date in SSRS?

In SSRS report query is generating date as a column in the format of :
Sales ID20200331 ID20200430 ID20200531
To remove the ID i used following expression:
=Right( Fields!ID20210331.Value, len(Fields!ID20210331.Value) - 2)
This gives me 84, instead of removing ID.
How can I remove ID and format date as 2020 Mar etc.
Thanks
If your fields values are "ID20200430" etc then in SSRS you can use something like this..
=DateSerial(
MID(Fields!IDDate.Value, 3, 4),
MID(Fields!IDDate.Value, 7, 2),
RIGHT(Fields!IDDate.Value, 2)
)
However It appears that it's your column [names] that represent dates is this correct?
If this is true, then you would have to UNPIVOT the columns in SQL then convert the resulting values into a real date format.
Here' some sample data to show how to do this.
DECLARE #t TABLE (Sales varchar(10), ID20200331 int, ID20200430 int, ID20200531 int)
INSERT INTO #t VALUES
('A', 1,2,3),
('B', 4,5,6),
('C', 7,8,9)
SELECT
Sales, IdDate, SomeNumber
, MyDate = DATEFROMPARTS(SUBSTRING(IdDate, 3, 4), SUBSTRING(IdDate, 7, 2), SUBSTRING(IdDate, 9, 2))
FROM #t
UNPIVOT(
SomeNumber FOR IdDate IN ([ID20200331],[ID20200430],[ID20200531])
) unpvt
Which gives us this including the myDate column which is the correct date type
You could then use this in a matrix control in SSRS to get the data back into a pivoted view

PostgresSQL Error - Issue with Real DataType

The following is the error I get for trying to insert a number for a column with the data type of real for a Postgres DB:
ERROR: invalid input syntax for type real: "40960.00"
CONTEXT: COPY table_of_interest, line 1, column col_1: "40960.00"
I am a bit of a noob when it comes to Postgres, I have much more experience with Oracle, MySQL, and Microsoft SQL Server. I can't figure out why this does not insert? In the CSV it is trying to insert from, the column is just a basic number column. That number does not contain the double quotes around it.
I am also getting a following error when trying to insert via python:
TypeError: not all arguments converted during string formatting
This is the first row I want to insert, as an example (error above still remains):
(Timestamp('2019-01-31 00:00:00'),
Timestamp('2018-10-03 00:00:00'),
'APP-552498',
'Company Name Lawyer',
'Funded',
36500,
1095.0,
1.35,
49275.0,
15509.0,
251.0,
'Daily',
1825.0,
196.31,
78,
0.0,
'Law Offices',
NaT,
'',
'CO',
8.4,
'Company Name',
0.7647,
38003.68,
7154.34,
'West',
33766.0,
'N')
I put the first two columns as type date, every column with a number as real, and the strings as character varying. Of course, the column that has NaT is also a date (and accordingly a datetime in python).
The following is the python code:
df_vals = [tuple(x) for x in df.values]
c.execute("""INSERT INTO schema.table VALUES (%s)""", df_vals[0])
c.executemany("""INSERT INTO schema.table VALUES (%s)""", df_vals)
where c is an already created cursor from conn.cursor()

PostgreSQL getting new id during insert

I need to create some customer number on record insert, format is 'A' + 4 digits, based on the ID. So record ID 23 -> A0023 and so on. My solution is currently this:
-- Table
create table t (
id bigserial unique primary key,
x text,
y text
);
-- Insert
insert into t (x, y) select concat('A',lpad((currval(pg_get_serial_sequence('t','id')) + 1)::text, 4, '0')), 'test';
This works perfectly. Now my question is ... is that 'safe', in the sense that currval(seq)+1 is guaranteed the same as the id column will receive? I think it should be locked during statement execution. Is this the correct way to do it or is there any shortcut to access the to-be-created ID directly?
Instead of storing this data, you could just query it each time you needed it, making the whole thing a lot less error-prone:
SELECT id, 'A' + LPAD(id::varchar, 4, '0')
FROM t

datestyle ignore format postgresql

I am trying to ignore an illegally formatted date in a csv file that I am uploading to postgresql through the command line:
Error: date/time field value out of range:"199999999"
The problem is, I cannot change the data in the csv file, so I have to find a way of importing this bad date as is.
Use an intermediate table (loaded_data) to store the data you get from you CSV. Make sure all the columns in that table are of type text, so that PostgreSQL will accept virtually anything (unless you have rows with the incorrect number of columns).
Once you have all your data in that table, sanitize all the columns so that when their values are incorrect you either set them to NULL, discard them (DELETE them) or set those columns to a default value. What you actually do will depend on your particular application.
The simplest (although probably not the fastest) way to sanitize your data is to use a function that CASTs your text to the appropriate type, and handles exceptions if the input is not well formatted. For the case of a date type, you can use the following function:
-- Create a function to get good dates... and return NULL if they're not
CREATE FUNCTION good_date(date_as_text text)
RETURNS DATE /* This is the type of the returned data */
IMMUTABLE STRICT /* If you pass a NULL, you'll get a NULL */
LANGUAGE PLPGSQL /* Language used to define the function */
AS
$$
BEGIN
RETURN CAST(date_as_text AS DATE) ;
EXCEPTION WHEN OTHERS THEN /* If something is wrong... */
RETURN NULL ;
END
$$ ;
Note that this function's behaviour will depend on your settings for datestyle. However, it will work always with texts like January 8, 1999, and will return NULL for dates such as 2017-02-30 or February 30, 2017.
You'll do the equivalent for a good_integer function.
Let's assume you have this input data:
CREATE TABLE loaded_data
(
some_id text,
some_date text
) ;
-- Let's assume this is the equivalent of loading the CSV...
INSERT INTO loaded_data
(some_id, some_date)
VALUES
(1, '20170101'),
(2, '19999999'),
(3, 'January 1, 1999'),
(4, 'February 29, 2001'),
(5, '20170230');
... and that you want to store this information in the following table:
CREATE TABLE destination_table
(
id integer PRIMARY KEY,
a_date date
) ;
... you'd use:
INSERT INTO destination_table
(id, a_date)
SELECT
good_integer(some_id) AS id, good_date(some_date) AS a_date
FROM
loaded_data ;
And you'd get:
SELECT * FROM destination_table;
id | a_date
-: | :---------
1 | 2017-01-01
2 | null
3 | 1999-01-01
4 | null
5 | null
Check all the setup at dbfiddle here
Alternative: use some ETL tool] that can perform equivalent functionality. The scenario I presented is, somehow, a very simple LTE (load, transform, extract) equivalent.

Hashbytes MD5 syntax

Why do the hashed results below differ? Shouldn't they be the same?
SELECT [teststring]
, SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', [teststring])), 3, 32)
, SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', 'HelloWorld')), 3, 32)
FROM [test]
WHERE [teststring]='HelloWorld'
HelloWorld 87434a4b7918d288dc1c1e0ca7544e77 68e109f0f40ca72a15e05cc22786f8e6
I can reproduce this, it would appear that your column is storing an NVARCHAR rather than a VARCHAR (which is what you have specified your string as in your query), these are stored differently and will therefore give different results.
If you run the following query you should see that they are the same when using the same datatype (NVARCHAR):
SELECT [teststring]
, SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', [teststring])), 3, 32)
, SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', N'HelloWorld')), 3, 32)
FROM [test]
WHERE [teststring]='HelloWorld'