Create an INSERT SQL query based on other queries - sql

I need to perform an INSERT query like this:
INSERT INTO Clients (ClientName, CountryID) VALUES ("STYLUS", 4)
But:
Only insert if ClientName (STYLUS for the example here) does not already exists
The CountryID (4 for the example here) must be retrieved from another query: SELECT CountryID FROM Countries WHERE CountryUK = 'FRANCE'
Is it possible to build a single SQL Query for all of this ?
Thanks.

For the first condition, you need a unique index/constraint on the table:
create unique index unq_clients_clientname;
Then, you can insert the value doing:
insert into clients(clientname, countryId)
select 'STYLUS', countryid
from countries
where countryuk = 'FRANCE';
This will return an error if you attempt to insert a duplicate value. If you don't want an error, then a database-independent method is:
insert into clients(clientname, countryId)
select 'STYLUS', countryid
from countries
where countryuk = 'FRANCE' and
not exists (select 1 from clients c2 where c2.clientname = 'STYLUS');

Being Simple,
if not exists(select * from Clients where Cientname='Stylus') begin insert into Clients select 'Stylus',Countryid from Countries where countryname='France' end
will do the work.Hope It helps.

Related

how to use insert statement with where clause from diff table in oracle without using plsql

I want to insert like below
If
select *from class where student_name='A' ;
then
Insert into student (Studnetname varchar2,rollno integer) values('A',1);
without using PL/SQL
Wouldn't that be as simple as
insert into student (studentname, rollno)
select student_name, rollno
from class
where student_name = 'A'
and rollno = 1;
If such a student (whose values satisfy the WHERE clause) exists, a row will be inserted. Otherwise, nothing will happen.
I want direct insert statement without select
The closest you will get to meeting this requirement is something like this:
Insert into student (Studnetname, rollno)
select 'A',1
from dual
where exists (select null from class where student_name = 'A' )
;
This will insert one row into STUDENT if there is at least one record in CLASS matching the given criterion.

Multiple Queries into 1 Query doing counts

Ok, trying to make this make sense and see if I can do this. I have multiple queries stored in SQL Server 2012 that I can run individually to get actual results. Each of these queries connect to a multitude of tables. What I want to do is take all of these queries and put them into a single query to get counts in one master list.
So for example. I have a query that looks for all records that have no email addresses. The next query looks for all records missing a phone number in a set field. The next query looks for records missing a filled field.
Each of these queries pull back results and I can run them one at a time. I want to set myself up a single query I can run to give me counts on each in a single results list.
I started doing a Union statement and put two of the query codes into it. The results came up like this:
NoEmail NoPhone
NULL 24486
74596 NULL
What I would like this to look like is this:
NoEmail NoPhone
74596 24486
Any ideas on how to do this?
I hope this is enough info and if not, let me know and I'll get you more.
Thanks.
You can do it like this:
Set up (for demonstration purposes only, so you can see the data I'm using):
create table t1 (
id numeric,
email varchar(20)
);
insert into t1 values (1,'test#example.com');
insert into t1 (id) values (2);
insert into t1 (id) values (3);
create table t2 (
id numeric,
phone varchar(20)
);
insert into t2 values (1,'123-456-7890');
insert into t2 (id) values (2);
insert into t2 (id) values (3);
insert into t2 (id) values (4);
insert into t2 (id) values (5);
Query:
select
(select count(id) from t1 where email is null) as NoEmail,
(select count(id) from t2 where phone is null) as NoPhone;
Result:
NoEmail NoPhone
2 4
You can add as many additional queries on to the end of the query as you'd like:
select
(select count(id) from t1 where email is null) as NoEmail,
(select count(id) from t2 where phone is null) as NoPhone,
(select ...) as anotherCol,
(select ...) as yetAnotherCol;

SQL Server Aggregate using like

I have a table with 2 columns, one is a 1/0 flag for whether they've opened an email, the second is the email address (ie joe123#domain.com).
Opened Email
0 joe123#domain.com
1 sue234#email.net
... ...
I'm trying to find if certain patterns in user names affect open rates by using regex patterns in LIKE but am unsure of the syntax for rows that match AND do NOT match the pattern.
For instance, I can do:
SELECT Email, sum(Opened)
FROM table1
WHERE Email LIKE '%joe%'
But this only gives me rows that match. I'd like rows that do and DON'T match in the same output.
I'd like to get something like this:
Pattern Opened
'joe' 55
not_joe 15987
'sue' 78
not_sue 15964
... ...
What's the best way to do this?
If you've already got a list of patterns, you can achieve the LIKE/NOT LIKE by using a CROSS JOIN (warning: performance hit).
See below for an example. Note: you can potentially improve the performance of the LIKE in the SELECT statement - there are other options available.
DECLARE #MatchList TABLE (ID INT, Pattern VARCHAR(3))
INSERT INTO #MatchList (ID, Pattern) VALUES (1, 'Joe')
INSERT INTO #MatchList (ID, Pattern) VALUES (2, 'Sue')
DECLARE #Table1 TABLE (Email VARCHAR(100))
INSERT INTO #Table1 (Email) VALUES ('joe123#domain.com')
INSERT INTO #Table1 (Email) VALUES ('sue234#email.net')
INSERT INTO #Table1 (Email) VALUES ('sue682#email.net')
INSERT INTO #Table1 (Email) VALUES ('a#domain.com')
INSERT INTO #Table1 (Email) VALUES ('b#domain.com')
INSERT INTO #Table1 (Email) VALUES ('c#domain.com')
INSERT INTO #Table1 (Email) VALUES ('d#domain.com')
INSERT INTO #Table1 (Email) VALUES ('e#domain.com')
SELECT
CASE WHEN Email LIKE '%'+Pattern+'%' THEN Pattern ELSE 'not_'+Pattern END AS Classification,
COUNT(*) Opened
FROM
#MatchList m
CROSS JOIN
#Table1
GROUP BY m.ID, CASE WHEN Email LIKE '%'+Pattern+'%' THEN Pattern ELSE 'not_'+Pattern END
ORDER BY m.ID
If i understood correctly you are trying to identify similar usernames
you can use a function like SOUNDEX to group your count by
SELECT
Email,
SOUNDEX(Email)
FROM TableA
SELECT COUNT(*) OpenedCount,
SOUNDEX(Email) EmailSOUNDEX
FROM TableA
GROUP BY SOUNDEX(Email)
ORDER BY OpenedCount desc
If all you want is something like all emails that have sue in it?
SELECT COUNT(*) OpenedCount,
SOUNDEX(Email) EmailSOUNDEX
FROM TableA
WHERE
Email like '%Sue%'
GROUP BY SOUNDEX(Email)
ORDER BY OpenedCount desc
For this kind of search maybe you can build a dictionary with relevant search terms and join it with
SELECT COUNT(*) OpenedCount,
SearchTermTable.Term
FROM TableA
JOIN SearchTermTable ON
TableA.Email like '%'+SearchTermTable.Term+'%'
WHERE
GROUP BY SearchTermTable.Term
ORDER BY OpenedCount desc

Return value cross join

I have two tables, one is a table #1 contains user information, email, password, etc..
the other table #2 contains item information
when I do a insert into table #2, and then use the returning statement, to gather what was inserted (returning auto values as well as other information), I also need to return information from table #1.
(excuse the syntax)
example:
insert into table #1(item,user) values('this item','the user')
returning *, select * from table 2 where table #1.user = table #2.user)
in other words, after the insert I need to return the values inserted, as well as the information about the user who inserted the data.
is this possible to do?
the only thing I came up with is using a whole bunch of subquery statements in the returning clause. there has to be a better way.
I suggest a data-modifying CTE (Postgres 9.1 or later):
WITH ins AS (
INSERT INTO tbl1(item, usr)
VALUES('this item', 'the user')
RETURNING usr
)
SELECT t2.*
FROM ins
JOIN tbl2 t2 USING (usr)
Working with the column name usr instead of user, which is a reserved word.
Use a subquery.
Simple demo: http://sqlfiddle.com/#!15/bcc0d/3
insert into table2( userid, some_column )
values( 2, 'some data' )
returning
userid,
some_column,
( SELECT username FROM table1
WHERE table1.userid = table2.userid
);

Updating Uncommitted data to a cell with in an UPDATE statement

I want to convert a table storing in Name-Value pair data to relational form in SQL Server 2008.
Source table
Strings
ID Type String
100 1 John
100 2 Milton
101 1 Johny
101 2 Gaddar
Target required
Customers
ID FirstName LastName
100 John Milton
101 Johny Gaddar
I am following the strategy given below,
Populate the Customer table with ID values in Strings Table
INSERT INTO CUSTOMERS SELECT DISTINCT ID FROM Strings
You get the following
Customers
ID FirstName LastName
100 NULL NULL
101 NULL NULL
Update Customers with the rest of the attributes by joining it to Strings using ID column. This way each record in Customers will have corresponding 2 matching records.
UPDATE Customers
SET FirstName = (CASE WHEN S.Type=1 THEN S.String ELSE FirstName)
LastName = (CASE WHEN S.Type=2 THEN S.String ELSE LastName)
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID
An intermediate state will be llike,
ID FirstName LastName ID Type String
100 John NULL 100 1 John
100 NULL Milton 100 2 Milton
101 Johny NULL 101 1 Johny
101 NULL Gaddar 101 2 Gaddar
But this is not working as expected. Because when assigning the values in the SET clause it is setting only the committed values instead of the uncommitted. Is there anyway to set uncommitted values (with in the processing time of query) in UPDATE statement?
PS: I am not looking for alternate solutions but make my approach work by telling SQL Server to use uncommitted data for UPDATE.
The easiest way to do it would be to split the update into two:
UPDATE Customers
SET FirstName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 1
And then:
UPDATE Customers
SET LastName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 2
There are probably ways to do it in one query such as a derived table, but unless that's a specific requirement I'd just use this approach.
Have a look at this, it should avoid all the steps you had
DECLARE #Table TABLE(
ID INT,
Type INT,
String VARCHAR(50)
)
INSERT INTO #Table (ID,[Type],String) SELECT 100 ,1 ,'John'
INSERT INTO #Table (ID,[Type],String) SELECT 100 ,2 ,'Milton'
INSERT INTO #Table (ID,[Type],String) SELECT 101 ,1 ,'Johny'
INSERT INTO #Table (ID,[Type],String) SELECT 101 ,2 ,'Gaddar'
SELECT IDs.ID,
tName.String NAME,
tSur.String Surname
FROM (
SELECT DISTINCT ID
FROM #Table
) IDs LEFT JOIN
#Table tName ON IDs.ID = tName.ID AND tName.[Type] = 1 LEFT JOIN
#Table tSur ON IDs.ID = tSur.ID AND tSur.[Type] = 2
OK, i do not think that you will find a solution to what you are looking for. From UPDATE (Transact-SQL) it states
Using UPDATE with the FROM Clause
The results of an UPDATE statement are
undefined if the statement includes a
FROM clause that is not specified in
such a way that only one value is
available for each column occurrence
that is updated, that is if the UPDATE
statement is not deterministic. For
example, in the UPDATE statement in
the following script, both rows in
Table1 meet the qualifications of the
FROM clause in the UPDATE statement;
but it is undefined which row from
Table1 is used to update the row in
Table2.
USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1
(ColA int NOT NULL, ColB decimal(10,3) NOT NULL);
GO
CREATE TABLE dbo.Table2
(ColA int PRIMARY KEY NOT NULL, ColB decimal(10,3) NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES(1, 10.0), (1, 20.0), (1, 0.0);
GO
UPDATE dbo.Table2
SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
FROM dbo.Table2
INNER JOIN dbo.Table1
ON (dbo.Table2.ColA = dbo.Table1.ColA);
GO
SELECT ColA, ColB
FROM dbo.Table2;
Astander is correct (I am accepting his answer). The update is not happening because of a read UNCOMMITTED issue but because of the multiple rows returned by the JOIN. I have verified this. UPDATE picks only the first row generated from the multiple records to update the original table. This is the behavior for MSSQL, Sybase and such RDMBMSs but Oracle does not allow this kind of an update an d it throws an error. I have verified this thing for MSSQL.
And again MSSQL does not support updating a cell with UNCOMMITTED data. Don't know the status with other RDBMSs. And I have no idea if anyRDBMS provides with in the query ISOLATION level management.
An alternate solution will be to do it in two steps, Aggregate to unpivot and then insert. This has lesser scans compared to methods given in above answers.
INSERT INTO Customers
SELECT
ID
,MAX(CASE WHEN Type = 1 THEN String ELSE NULL END) AS FirstName
,MAX(CASE WHEN Type = 2 THEN String ELSE NULL END) AS LastName
FROM Strings
GROUP BY ID
Thanks to my friend Roji Thomas for helping me with this.