Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uoqP7-00BJw5-IW for pgsql-general@arkaria.postgresql.org; Wed, 20 Aug 2025 21:31:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uoqP6-00BcqV-RB for pgsql-general@arkaria.postgresql.org; Wed, 20 Aug 2025 21:31:33 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uoqP6-00BcqM-Fa for pgsql-general@lists.postgresql.org; Wed, 20 Aug 2025 21:31:33 +0000 Received: from mail-ed1-x534.google.com ([2a00:1450:4864:20::534]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1uoqP4-000ydg-2p for pgsql-general@lists.postgresql.org; Wed, 20 Aug 2025 21:31:32 +0000 Received: by mail-ed1-x534.google.com with SMTP id 4fb4d7f45d1cf-6188b6f501cso462973a12.2 for ; Wed, 20 Aug 2025 14:31:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1755725489; x=1756330289; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=7a5I5tU3wT+a/pn/mVILx0Z0NXrdWgoUY+8mvdnh1H0=; b=UERZp6gBo/b5oh4G7tGzhYPwb3v0/J2TeLADOJ7wm3rAh6HPWgY8JLab7c2Z5P7po8 8BwvgOgfX2vEmEhDHOknMw15nKR4z39AobHaeqDrayOAPb1FF4MY1p4rVa10+NGgYr2L xvvLa4iFVpHbo5HVaTG5fa6b38/Tb65PmFSErGWbHW96e9Ipaqbf1JB/Hf793QS5xADk BEuKyU2OyWT7QmysGotdjSiq2AvuY/1K8xAedJPv65O6FwnTng/o4tDVYyWTNfA9uluV xQ7TKQGqV67R84GXg6IXum09gvUNoOANtaoC2MNa0KkY/3DKHAl160GUyDb97osoCB1G wo5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755725489; x=1756330289; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=7a5I5tU3wT+a/pn/mVILx0Z0NXrdWgoUY+8mvdnh1H0=; b=BMC+JDuFxMHMXhDlyGsJqHcplkeO0eikFXMaLQNqBVlMVZLLiWnpAEDvIbQWZX70RG KFUEaGvZWl1SHqfP746ZhkFFg3t9JU8XLLi3x6cb01eZgsSiSk9kN8rGDchXFRvEaqIp +SPdgG78VntWK5jd3iieLFzRba1DY1i7IHlUJLTdGLZpIAWgoWB9D6jAVW54kQz7af7B AqdahW9Ljac5GDwTQdsloVB+aKwz7l7ZTakQB7F4faLQetP+PUvnw+kznRM27ay1rRLk bUax1pVwzM2ZN5BwaSqcD/CJp5T4GNmrOYyBsHD4KIvMBq32Xc5cZF7dyBmmMbf4PEjD jOVQ== X-Forwarded-Encrypted: i=1; AJvYcCXpOR8sf57nG0BwtpYfd5IIJhUabRFo0sN73hvV2ESOqGM4Z1yT0vL2kgnbnElYz+CqtqUisTlVnoiNXXcy@lists.postgresql.org X-Gm-Message-State: AOJu0YwHNCnEHjJ3xnXFTfQQ3p+lSANUbknXw+vH2DXah7SmVR41mpvV nwc/lSnuAkUKJLawCkDmuTAbPGWLIjLH0mV6K8onAwqGkv6auWuTJKLmDSgqtt3eITQMJK1xtN3 fpgTquF3Ho8XCqOgjWawGrN8/+pP+9L4= X-Gm-Gg: ASbGncsnvhIpNedYS0qGQolheGdn/XS5B9gC8IvOicr9zJOzubHJT3UrqOl5PZqvmQY NSfnNrS/y3lSuHGLIdzU0Nt99SMtsj65mYyWdZ++mYx1e1eZmYQwIM+aNDQKy49+sqmqrsKDz2J KbVOl6le3qBA5h5ge990sItnffudvykNpslP9cvvrTCWMdb5vRilHv3e0o0QDzJab8b92+C8A/K zHsSXQ= X-Google-Smtp-Source: AGHT+IGAAy735JKspFAAV0p2a2H4bABIYCzc9XdhEeI4OJgS9BQrMun9gZEzzD7e9aFnTHeEcP8wFTw5zW9tA8gRhgA= X-Received: by 2002:a05:6402:2714:b0:617:b3e8:97aa with SMTP id 4fb4d7f45d1cf-61bf86d813dmr177030a12.3.1755725489243; Wed, 20 Aug 2025 14:31:29 -0700 (PDT) MIME-Version: 1.0 References: <48AA15E9-1979-489D-B94E-5FE2972A6AD2@gmail.com> In-Reply-To: <48AA15E9-1979-489D-B94E-5FE2972A6AD2@gmail.com> From: Justin Date: Wed, 20 Aug 2025 17:31:16 -0400 X-Gm-Features: Ac12FXz6fltttDrcJW3zrHVHpoT5bzehh9MltBuUiSTMXHjyHVtqIbH1ZT5H-1k Message-ID: Subject: Re: MS SQL to Postgres To: Alban Hertroys Cc: KK CHN , pgsql-general@lists.postgresql.org Content-Type: multipart/alternative; boundary="0000000000001c09a0063cd2b2c1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000001c09a0063cd2b2c1 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, Aug 20, 2025 at 4:15=E2=80=AFPM Alban Hertroys = wrote: > > > On 20 Aug 2025, at 19:25, KK CHN wrote: > > (=E2=80=A6) > > > 4. Any hurdles or challenges or risks > > MS SQL defaults to case insensitive string comparisons, trimming trailing > white-space. > > PostgreSQL defaults to case sensitive string comparisons, so incorrectly > cased strings in queries that match in MS SQL will not match in PostgreSQ= L. > > The trailing spaces bit is not going to matter while moving the data to > Postgres, as you will not get any trailing spaces from MS SQL to be store= d > in PostgreSQL (they=E2=80=99ve been trimmed already, after all) - but it = could > trigger some application bugs where people have assumed that trailing > spaces get trimmed. > > Also, time zone names are wildly different between the two. MS SQL uses > Microsoft Windows time zone names, Postgres (and most other RDBMSes) use > IANA names. > > Alban Hertroys > -- > There is always an exception to always. > > > Moving the data and schema are the easy part, it's all minor differences in the SQL implementation that bite big time. CASE SENSITIVE vs CASE INSENSITIVE for searching Sessions/Connections can't jump databases in PostgreSQL have to create a new connection while in MSSQL if the user has permissions can connect to any database using fully qualified names database.schema.table. This is not possible in PostgreSQL there are workarounds using FDW, which is hackish. PostgreSQL object names are case insensitive unless using double quotes. example MyTable =3D=3D mytable to make case sensitive have to use double quote like so SELECT * FROM "MyTable" Name of common functions differ LEN() =3D=3D LENGTH() there are lots of th= ese.. LIMIT OFFSET are completely different structure How Transactions are handled you need to read up on PostgreSQL MVCC vs the MSSQL default transaction handling and Isolation level. MSSQL can be made to work like MVCC via SNAPSHOT isolation; it has to be turned on as its off by default. Depending on how MSSQL is being used the locking behavior can be very different. Read up on pessimistic vs optimistic locking, PostgreSQL operates in optimistic locking mode by default, while MSSQL operates in a pessimistic locking mode by default. PostgreSQL can not read rows/transactions that have NOT been committed, this is possible in MSSQL with "TRANSACTION ISOLATION LEVEL READ UNCOMMITTED" PostgreSQL will ignore that command.... Postgresql operates in Implicit Transaction mode means every command is treated as a separate transaction unless it sees a BEGIN. While MSSQL does not operate that way it expects to see a BEGIN. MSSQL can automatically add the BEGIN using the SET IMPLICIT_TRANSACTIONS ON There are a bunch of gotchas like this that are not found during testing unless you are looking for them.. Thank you Justin --0000000000001c09a0063cd2b2c1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

On Wed, Aug 20, 202= 5 at 4:15=E2=80=AFPM Alban Hertroys <haramrae@gmail.com> wrote:

> On 20 Aug 2025, at 19:25, KK CHN <kkchn.in@gmail.com> wrote:

(=E2=80=A6)

> 4. Any hurdles or challenges or risks

MS SQL defaults to case insensitive string comparisons, trimming trailing w= hite-space.

PostgreSQL defaults to case sensitive string comparisons, so incorrectly ca= sed strings in queries that match in MS SQL will not match in PostgreSQL.
The trailing spaces bit is not going to matter while moving the data to Pos= tgres, as you will not get any trailing spaces from MS SQL to be stored in = PostgreSQL (they=E2=80=99ve been trimmed already, after all) - but it could= trigger some application bugs where people have assumed that trailing spac= es get trimmed.

Also, time zone names are wildly different between the two. MS SQL uses Mic= rosoft Windows time zone names, Postgres (and most other RDBMSes) use IANA = names.

Alban Hertroys
--
There is always an exception to always.



Moving the data and schema are the= easy part,=C2=A0 it's all minor differences in the SQL implementation = that bite big time.=C2=A0

CASE SENSITIVE vs CASE INSENSITIVE for se= arching=C2=A0

Sessions/Connections can't jump databas= es in PostgreSQL have to create a new connection while in MSSQL if the user= has permissions can connect to any database using fully qualified names da= tabase.schema.table.=C2=A0 This is not possible in PostgreSQL=C2=A0 there a= re workarounds=C2=A0using FDW, which is hackish.

PostgreSQL o= bject names are case insensitive unless using double quotes.=C2=A0 example= =C2=A0 =C2=A0MyTable =3D=3D mytable=C2=A0 to make case sensitive have to us= e double quote like so SELECT * FROM=C2=A0 "MyTable"

Name = of common=C2=A0functions differ LEN() =3D=3D LENGTH()=C2=A0 there are lots = of these..
=C2=A0
LIMIT OFFSET=C2=A0are completely different structur= e

How Transactions are handled=C2=A0 you need to read up on PostgreS= QL MVCC vs the MSSQL default transaction handling and Isolation level.=C2= =A0 MSSQL can be made to work like MVCC via SNAPSHOT isolation; it has to b= e turned on as its off by default.

Depending on how MSSQL is being u= sed the locking behavior can be very different. Read up on pessimistic=C2= =A0vs optimistic locking,=C2=A0 PostgreSQL operates in optimistic locking m= ode by default,=C2=A0 while MSSQL operates in a pessimistic locking mode by= default.=C2=A0=C2=A0

PostgreSQL can not read rows/transactions that= =C2=A0have NOT been committed, this is possible in MSSQL=C2=A0 with=C2=A0 &= quot;TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"=C2=A0 PostgreSQL wi= ll ignore that command....

Postgresql operates in Implicit Transacti= on mode means every command is treated as a separate=C2=A0transaction unles= s it sees a BEGIN.=C2=A0 While MSSQL does not operate that way=C2=A0 it exp= ects to see a BEGIN.=C2=A0 MSSQL can automatically add the BEGIN using the= =C2=A0SET IMPLICIT_TRANSACTIONS ON =C2=A0

There are a bunch of gotch= as like this that are not found during testing unless you are looking for t= hem..

Thank you
Justin





=C2=A0

=C2= =A0
--0000000000001c09a0063cd2b2c1--