How to insert multiple rows in a pgsql table, if the table is empty? - database

I'm developing a Building Block for Blackboard, and have run into a database related issue.
I'm trying to insert four rows into a pgsql table, but only if the table is empty. The query runs as a post-schema update, and is therefore run whenever I re-install the building block. It is vital that I do not simply drop exsisting values and/or replace them (which would be a simple and effective solution otherwise).
Below is my existing query, that does the job, but only for one row. As I mentioned, I'm trying to insert four rows. I can't simply run the insert multiple times, as after the first run, the table would no longer be empty.
Any help will be appriciated.
BEGIN;
INSERT INTO my_table_name
SELECT
nextval('my_table_name_SEQ'),
'Some website URL',
'Some image URL',
'Some website name',
'Y',
'Y'
WHERE
NOT EXISTS (
SELECT * FROM my_table_name
);
COMMIT;
END;

I managed to fix the issue.
In this post, #a_horse_with_no_name suggest using UNION ALL to solve a similar issue.
Also thanks to #Dan for suggesting using COUNT, rather than EXISTS
My final query:
BEGIN;
INSERT INTO my_table (pk1, coll1, coll2, coll3, coll4, coll5)
SELECT x.pk1, x.coll1, x.coll2, x.coll3, x.coll4, x.coll5
FROM (
SELECT
nextval('my_table_SEQ') as pk1,
'Some website URL' as coll1,
'Some image URL' as coll2,
'Some website name' as coll3,
'Y' as coll4,
'Y' as coll5
UNION
SELECT
nextval('my_table_SEQ'),
'Some other website URL',
'Some other image URL',
'Some other website name',
'Y',
'N'
UNION
SELECT
nextval('my_table_SEQ'),
'Some other other website URL',
'Some other other image URL',
'Some other other website name',
'Y',
'N'
UNION
SELECT
nextval('my_table_SEQ'),
'Some other other other website URL',
'Some other other other image URL',
'Some other other other website name',
'Y',
'Y'
) as x
WHERE
(SELECT COUNT(*) FROM my_table) <= 0;
COMMIT;
END;

It is better if you count the rows because it gets the number of input rows.
This should work:
BEGIN;
INSERT INTO my_table_name
SELECT
nextval('my_table_name_SEQ'),
'Some website URL',
'Some image URL',
'Some website name',
'Y',
'Y'
WHERE
(SELECT COUNT(*) FROM my_table_name)>0
COMMIT;
END;

Inserts won't overwrite, so I'm not understanding that part of your question.
Below are two ways to insert multiple rows; the second example is a single sql statement:
create table test (col1 int,
col2 varchar(10)
) ;
insert into test select 1, 'A' ;
insert into test select 2, 'B' ;
insert into test (col1, col2)
values (3, 'C'),
(4, 'D'),
(5, 'E') ;
select * from test ;
1 "A"
2 "B"
3 "C"
4 "D"
5 "E"

Related

Looking for better way of writing a code logic

I have the following code with a CASE statement:
--to check if any record with this conditon present in table
--then pick col1, if such record exists
CASE WHEN EXISTS (SELECT col1 from table where col2=1 and col3 is not null)
THEN (SELECT col1 from table where col2=1 and col3 is not null)
ELSE
<something else>
END
Condition in the where are many more and code looks so big. Can see repeting also in WHEN case and THEN case.
Any better way to rewrite the code. with no impact on performance
I'm not sure how the query you listed would work, is it part of a larger query? Part of a SET statement? I think what you're looking for may be pulling the SELECT outside your CASE, like this
;with cteSampleData as (
SELECT * FROM (VALUES ('Row 1', 1, NULL)
,('Row 2', 1, 'Also row 2')
,('Row 3', 2, NULL)
,('Row 4', 2, 'Also row 4')
,('Row 5', 1, 'Also row 5')
) as SampleData(Col1, Col2, Col3)
)SELECT SD.Col1, SD.Col2, SD.Col3,
CASE WHEN col2=1 and col3 is not null
THEN col1
ELSE
CONCAT('Anything other than ', Col1)
END as MyCase
FROM cteSampleData as SD
Note that in the query you wrote, you would potentially return multiple rows in your THEN clause, which I think is an error regardless of settings, but at least is an error in the default SQL Server configuration.

I have two tables I want to retrieve the different results from same column in SQL

I have listed the actual table. From that I want the result as expected one.
Your issue is not that you have written in your problem. You first go to learn how to normalize the SQL or Tabular data. When you apply the second normal form this issue is resolved.
The given link provides a better understanding of normalization.
Normalization in SQL Tables
try this
CREATE TABLE demo (
jobPreference varchar(255),
Triggered varchar(255),
Success varchar(255),
opened varchar(255));
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('email-pwd reset', 'yes', 'success','yes');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('email-pwd reset', 'yes', 'success','yes');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('email-pwd reset', 'yes', 'fail','no');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('email-statement', 'yes', 'success','no');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('email-EMI reminder', 'yes', 'fail','no');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('SMS-loan EMI', 'yes', 'fail','no');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('SMS-confirmation', 'yes', 'fail','no');
INSERT INTO demo(jobPreference,Triggered,Success,opened) VALUES ('SMS-confirmation', 'yes', 'success','yes');
select SUBSTRING(jobPreference,0,CHARINDEX('-',jobPreference,0)) as Splitted
,jobPreference
,count(case Triggered when 'yes' then 1 else null end) as TriggeredCount
,count(case Success when 'success' then 1 else null end) as SuccessCount
,count(case opened when 'yes' then 1 else null end) as openedCount
from demo
group by jobPreference
For demo : https://rextester.com/ANPN26483

Recording Multiple Rows of Data from Table Insertion Using Trigger

I tried creating a trigger to store the data manipulations done on my Food table inside another table called FoodTriggerTable. When I insert only one row of data, I can record the data manipulation well in FoodTriggerTable. However, when I insert multiple rows at once, I only store the information of the first row of data. I have the following trigger:
CREATE TRIGGER InsertFoodTrigger ON Food
AFTER INSERT
AS
DECLARE #FoodID varchar(5);
DECLARE #FoodName nvarchar(50);
DECLARE #FoodDesc nvarchar(200);
DECLARE #FoodPrice money;
DECLARE #InsertAction varchar(200);
DECLARE #InsertActionTime datetime;
DECLARE #Amount int;
SELECT #FoodID = i.FoodID FROM INSERTED i;
SELECT #FoodName = i.FoodName FROM INSERTED i;
SELECT #FoodDesc = i.FoodDesc FROM INSERTED i;
SELECT #FoodPrice = i.FoodPrice FROM INSERTED i;
SELECT #Amount = COUNT(*) FROM INSERTED i;
SET #InsertAction = 'You''ve inserted ' + CONVERT(varchar(10), #Amount) + ' data into ''Food'' table';
INSERT INTO FoodTriggerTable (FoodID, FoodName, FoodDesc, FoodPrice, InsertAction, InsertActionTime)
VALUES (#FoodID, #FoodName, #FoodDesc, #FoodPrice, #InsertAction, GETDATE());
GO
And I tried the following INSERT:
INSERT INTO Food
VALUES ('CH006', 'Dummy Data 1', 'Dummy data', '0', '34'),
('CH007', 'Dummy Data 2', 'Dummy data', '0', '75');
How do I fix my trigger so that it also records the second row of data manipulation?
You need to think set based - inserted is a table, with a row for each record inserted or updated. Just use it as you would a normal table - don't try and convert it to procedural programming e.g.
INSERT INTO FoodTriggerTable (FoodID, FoodName, FoodDesc, FoodPrice, InsertAction, InsertActionTime)
select FoodId, FoodName, FoodDesc, FoodPrice, null, getdate()
from Inserted
Note: Not sure what InsertAction you want when its 1 per row now - up to you.
Edit: Procedural is actually the correct term. When doing stuff in T-SQL you are generally manipulating sets of data, which is whats its designed to do, given its a database programming language. So generally you try to frame and solve the problem in terms of sets of data. This is quite apparent when writing a trigger because and insert/update/delete could involve any number of records and you have to handle that. You can of course use cursors and loops to drop back to procedural programming but performance is going to suffer. There are many articles about this out there, here is an example https://www.sqlshack.com/introduction-set-based-vs-procedural-programming-approaches-t-sql/
CREATE TRIGGER InsertFoodTrigger ON Food
AFTER INSERT
AS
INSERT INTO FoodTriggerTable (FoodID, FoodName, FoodDesc, FoodPrice, InsertAction, InsertActionTime)
SELECT FoodID, FoodName, FoodDesc, FoodPrice, 'You''ve inserted ' + CONVERT(varchar(10), (SELECT COUNT(*) FROM inserted)) + ' data into ''Food'' table', GETDATE()
FROM inserted
GO

Update inserts different hash values than a select does

I am trying to update a new column in my SQL Server user table with the hash of another column.
when I test the conversion with a select statement it will return the correct MD5 hash that I get from online hash generators.
select CONVERT(VARCHAR(32), HashBytes('MD5', 'valuetohash'), 2)
when I use this same conversion in an update statement as shown below I get a different value, inserted then the select statement with the same value hashed.
UPDATE users SET [newcolumn1] = CONVERT(VARCHAR(32), HashBytes('MD5', column1), 2)
what am I doing wrong?
The value you have in users.column1 does not exactly match the value you are manually passing through HashBytes as a test. To confirm that this works when the values are the same, try:
DECLARE #users TABLE (
column1 VARCHAR(100),
newcolumn1 VARCHAR(32)
)
INSERT INTO #users
SELECT 'some text', NULL
SELECT CONVERT(VARCHAR(32), HashBytes('MD5', 'some text'), 2)
UPDATE #users SET newcolumn1 = CONVERT(VARCHAR(32), HashBytes('MD5', column1), 2)
SELECT newcolumn1 FROM #users
You'll see that the results you get from each SELECT are the same, because the values of 'some text' and #users.column1 are identical.
Try comparing your values first:
SELECT CASE WHEN column1 = 'expectedValue'
THEN 'MATCH'
ELSE 'DIFFERENCE'
END AS MatchCheck
FROM users
or
SELECT column1
FROM users
WHERE column1 = 'expectedValue'
If you get results from the first query where MatchCheck = 'MATCH' or results from the second query at all, then you should also get results form your UPDATE which give the hash you expect, as the values are the same.
As mentioned by ughai in the comments, it's most likely you have some spaces or non-printable characters in the values in your database which you are not including when you dry-run the hashing, hence the different results.

Updating long string through SQL Server Query Analyzer

I have a really long string of text that I would like to update a particular column in a table. The update statement in sql query analyzer is on one long line currently. Is there a way to break up the update statment into multiple lines for easier reading of the update statement?
Query analyzer lets you put line breaks into literals:
insert into tbl (x) values ('hello
world')
But this inserts a CR as well. The other suggestion:
insert into tbl (x) values ('hello ' +
'world')
is standard procedure.
There's no problem having an UPDATE statement over multiple lines. Something like:
UPDATE yourtable
SET col1 =
'New value for column 1'
,col2 =
'New value for column 2'
WHERE col3 = 7
...is just fine.
I think what you are after is string concatenation?
You can do an update like this:
Update YourTable
Set Col1 = 'Start of some long string' +
'End of the long string'
Where SomeColumn = SomeValue

Resources