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

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

Related

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

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

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"

Using ISNUMERIC fails in condition

I have a table like this (simplified):
CREATE TABLE #table (Id INT, Field NVARCHAR(MAX))
INSERT INTO #table VALUES (1, 'SomeText')
INSERT INTO #table VALUES (2, '1234')
For some reasons I need to query this table and get the sum of Field if it is numeric and return '' if it is not. I tried it like this:
SELECT CASE WHEN ISNUMERIC(Field) = 1 THEN SUM(CONVERT(MONEY, Field)) ELSE '' END
FROM #table
GROUP BY Field
But this query leads to the following exception:
Cannot convert a char value to money. The char value has incorrect syntax.
I even changed the ELSE case from '' to 0 but I still get the same message.
Why do I get the exception? As far as I know, SUM(...) should not be executed when ISNUMERIC(Field) returns 0.
Select sum(case when ISNUMERIC(Field)=1 then cast(field as money) else 0 end)
from #table
Group By Field
Returns
(No column name)
1234.00
0.00
Working with mixed datatypes can be a real pain. Where possible, consider table designs that avoid this. To further complicate matters, IsNumeric does not always return what you might expect.
Filtering out the non-numerics before aggregating is one way to go:
SELECT
SUM(CONVERT(MONEY, Field))
FROM
#table
WHERE
ISNUMERIC(Field) = 1
GROUP BY
Field
;

TSQL trigger instead of insert

I need to replace, after an insert in a certain table, one of the column value if it match with a banned value.
example:
INSERT INTO [dbo].[TEST_A]
([COL_A]
,[COL_B])
VALUES
('TEST'
,'TEST1')
TEST1 is a banned value and I want to replace it in 'BANNED'.
This is the trigger I wrote but it seems to working properly well:
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,REPLACE(COL_B, 'TEST1', 'BANNED')
FROM inserted
WHERE INSERTED.COL_B IN ('TEST1')
The error is that if I insert a different value in COL_B no rows are inserted.
Can you give me a solution?
thanks in advance
If you have more values than you want to put in a case statement, you can try using a table to store the banned words and the replacement for them. Then join to that in the insert, something like:
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,CASE WHEN b.banned is null then i.col_b
ELSE b.replacement
END
FROM inserted i
LEFT JOIN Banned b on i.col_B = b.banned
You need to modify your trigger.
CREATE TRIGGER [dbo].[TEST_NAME_INS] ON [dbo].[TEST_A]
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TEST_A
(COL_A
,COL_B)
SELECT
COL_A
,CASE WHEN COL_B ='TEST1' THEN 'BANNED'
WHEN COL_B ='TEST12' THEN 'BANNED34'
ELSE COL_B END
FROM inserted

Create #TableVariable based on an existing database table?

I want to use table variables in stored procedures but here is an issue. My tables are very large and declaring a table variable need a long code to write and debug as well.
Kindly advice me some way to declare table variables quickly, is it possible to create table variable based on an existing table ?
Or please share any tip to create code for creating table variable.
Thanks
Right click the table, choose Script As Create.
Replace create table xxx with declare #xxx table.
As discussed in this SO Question you can't select into a table variable.
When you say "large", if you mean a lot of columns, the best approach for you would probably be to script that table as create and save the definition and use that in your Declare statement.
If you mean large as far as the number of rows you'll have in the table variable, you may want to consider using a temporary table which you could then do a SELECT INTO statement to create it based off of the original.
SELECT * INTO #tmpTable FROM srcTable
The simple answer is "No you cannot create a variable table based on other table"
But, you can generalise a bit by using a type table.
For example (note: you can add documentation to the type table and columns, which can be useful for future reference):
PRINT 'type: [dbo].[foo_type]'
PRINT ' - Check if [dbo].[foo_type] TYPE exists (and drop it if it does).'
GO
IF EXISTS (SELECT 1 FROM sys.types WHERE name = 'foo_type' AND is_table_type = 1 AND SCHEMA_ID('dbo') = schema_id)
BEGIN
-- Create the proc
PRINT ' - Drop TYPE [dbo].[foo_type]';
DROP TYPE [dbo].[foo_type];
END;
GO
PRINT ' - create [dbo].[foo_type] TYPE.'
GO
CREATE type [dbo].[foo_type] as Table
(
[id] int identity(1,1) PRIMARY KEY
, [name] varchar(255) NOT NULL
, [description] varchar(255)
, numeric_data numeric(26, 6)
, datetimestamp datetime default getdate()
, Unique_Indicator float unique not null default cast(getdate() as float)
, CHECK (Unique_Indicator > 0)
);
GO
PRINT ' - done.'
GO
-- Adding the descriptions
PRINT ' - Adding Type level Description'
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'describe the usage of this type.' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TYPE',#level1name=N'foo_type'
GO
PRINT ' - Adding Column level Descriptions'
PRINT ' - column: id'
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'ID of the record...' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TYPE',#level1name=N'foo_type', #level2type=N'COLUMN',#level2name=N'ID';
GO
------------------------------------------------------------------------------------------------
-- use the type defined above to manipulate the variable table:
declare #foo_table foo_type;
--insert using the default value for the for the unique indicator.
insert into #foo_table (name, [description], numeric_data, datetimestamp)
values('babar', 'this is the king of the elephants', 12.5, '1931-01-01')
;
-- insert the records one by one to use the scope_identity() for the unique indicator.
insert into #foo_table (name, [description], numeric_data, datetimestamp, Unique_Indicator )
values('zephyr', 'Babar''s monkey friend', 5.5, '1932-01-01', scope_identity())
;
insert into #foo_table (name, [description], numeric_data, datetimestamp, Unique_Indicator )
values ('Celeste', 'Babar''s sister', 19.5, '1932-01-01', scope_identity())
;
-- insert using a list of values
insert into #foo_table (name, [description], numeric_data, datetimestamp, Unique_Indicator )
values('Babur', 'Not Babar!!!', 1483, '1983-02-14', 10)
, ('Mephistopheles', 'Not Babar either...', 666, '1866-01-01',11)
;
-- insert using a select
insert into #foo_table (name, [description], numeric_data, datetimestamp, Unique_Indicator)
(select 'Conan', 'The Cimmerian barbarian', 850, '1932-12-01',99 union
select 'Robert E. Howard', 'Conan''s creator', 30, '1906-01-22', 100
);
-- check the data we inserted in the variable table.
select * from #foo_table;
-- Clean up the example type
DROP TYPE [dbo].[foo_type];

Resources