Multiple Queries into 1 Query doing counts - sql

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;

Related

Select Rows with Longest Unique Strings

I'm trying to figure out how to select a subset of rows from a table, with the longest unique string for each "parent" string. I'll provide table examples below and my code that didn't work.
Current Table:
Name
SalePrice
NorthAmerica\US\Northeast\NewYork
8576
NorthAmerica\US\Northeast
2598
SouthAmerica\Brazil
1348
SouthAmerica\Chile\NorthEast
9726
SouthAmerica\Chile
4412
NorthAmerica\Canada\Ontario
3894
NorthAmerica\Canada
6321
Desired Output:
Name
SalePrice
NorthAmerica\US\Northeast\NewYork
8576
SouthAmerica\Brazil
1348
SouthAmerica\Chile\NorthEast
9726
NorthAmerica\Canada\Ontario
3894
Originally, I thought I could apply some form of logic based off the number of backslashes (
example: SELECT * FROM TestTable WHERE Name LIKE '%\\%'
). However, this logic doesn't work because some names furthest branch may only have 1 backslash while others may have 3+.
Code to generate test table is below and any help/advice would be greatly appreciated
create table t1(
[name] varchar(60),
[saleprice] int );
insert into t1 values ('NorthAmerica\US\Northeast\NewYork',8576);
insert into t1 values ('NorthAmerica\US\Northeast',2598);
insert into t1 values ('SouthAmerica\Brazil',1348);
insert into t1 values ('SouthAmerica\Chile\NorthEast',9726);
insert into t1 values ('SouthAmerica\Chile',4412);
insert into t1 values ('NorthAmerica\Canada\Ontario',3894);
insert into t1 values ('NorthAmerica\Canada',6321);
Use the operator LIKE with NOT EXISTS:
SELECT t1.*
FROM t1
WHERE NOT EXISTS (
SELECT 1
FROM t1 AS t2
WHERE t2.name LIKE t1.name + '_%'
);
See the demo.

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
);

Move SQL data from one table to another

I was wondering if it is possible to move all rows of data from one table to another, that match a certain query?
For example, I need to move all table rows from Table1 to Table2 where their username = 'X' and password = 'X', so that they will no longer appear in Table1.
I'm using SQL Server 2008 Management Studio.
Should be possible using two statements within one transaction, an insert and a delete:
BEGIN TRANSACTION;
INSERT INTO Table2 (<columns>)
SELECT <columns>
FROM Table1
WHERE <condition>;
DELETE FROM Table1
WHERE <condition>;
COMMIT;
This is the simplest form. If you have to worry about new matching records being inserted into table1 between the two statements, you can add an and exists <in table2>.
This is an ancient post, sorry, but I only came across it now and I wanted to give my solution to whoever might stumble upon this one day.
As some have mentioned, performing an INSERT and then a DELETE might lead to integrity issues, so perhaps a way to get around it, and to perform everything neatly in a single statement, is to take advantage of the [deleted] temporary table.
DELETE FROM [source]
OUTPUT [deleted].<column_list>
INTO [destination] (<column_list>)
All these answers run the same query for the INSERT and DELETE. As mentioned previously, this risks the DELETE picking up records inserted between statements and could be slow if the query is complex (although clever engines "should" make the second call fast).
The correct way (assuming the INSERT is into a fresh table) is to do the DELETE against table1 using the key field of table2.
The delete should be:
DELETE FROM tbl_OldTableName WHERE id in (SELECT id FROM tbl_NewTableName)
Excuse my syntax, I'm jumping between engines but you get the idea.
A cleaner representation of what some other answers have hinted at:
DELETE sourceTable
OUTPUT DELETED.*
INTO destTable (Comma, separated, list, of, columns)
WHERE <conditions (if any)>
Yes it is. First INSERT + SELECT and then DELETE orginals.
INSERT INTO Table2 (UserName,Password)
SELECT UserName,Password FROM Table1 WHERE UserName='X' AND Password='X'
then delete orginals
DELETE FROM Table1 WHERE UserName='X' AND Password='X'
you may want to preserve UserID or someother primary key, then you can use IDENTITY INSERT to preserve the key.
see more on SET IDENTITY_INSERT on MSDN
You should be able to with a subquery in the INSERT statement.
INSERT INTO table1(column1, column2) SELECT column1, column2 FROM table2 WHERE ...;
followed by deleting from table1.
Remember to run it as a single transaction so that if anything goes wrong you can roll the entire operation back.
Use this single sql statement which is safe no need of commit/rollback with multiple statements.
INSERT Table2 (
username,password
) SELECT username,password
FROM (
DELETE Table1
OUTPUT
DELETED.username,
DELETED.password
WHERE username = 'X' and password = 'X'
) AS RowsToMove ;
Works on SQL server make appropriate changes for MySql
Try this
INSERT INTO TABLE2 (Cols...) SELECT Cols... FROM TABLE1 WHERE Criteria
Then
DELETE FROM TABLE1 WHERE Criteria
You could try this:
SELECT * INTO tbl_NewTableName
FROM tbl_OldTableName
WHERE Condition1=#Condition1Value
Then run a simple delete:
DELETE FROM tbl_OldTableName
WHERE Condition1=#Condition1Value
You may use "Logical Partitioning" to switch data between tables:
By updating the Partition Column, data will be automatically moved to the other table:
here is the sample:
CREATE TABLE TBL_Part1
(id INT NOT NULL,
val VARCHAR(10) NULL,
PartitionColumn VARCHAR(10) CONSTRAINT CK_Part1 CHECK(PartitionColumn = 'TBL_Part1'),
CONSTRAINT TBL_Part1_PK PRIMARY KEY(PartitionColumn, id)
);
CREATE TABLE TBL_Part2
(id INT NOT NULL,
val VARCHAR(10) NULL,
PartitionColumn VARCHAR(10) CONSTRAINT CK_Part2 CHECK(PartitionColumn = 'TBL_Part2'),
CONSTRAINT TBL_Part2_PK PRIMARY KEY(PartitionColumn, id)
);
GO
CREATE VIEW TBL(id, val, PartitionColumn)
WITH SCHEMABINDING
AS
SELECT id, val, PartitionColumn FROM dbo.TBL_Part1
UNION ALL
SELECT id, val, PartitionColumn FROM dbo.TBL_Part2;
GO
--Insert sample to TBL ( will be inserted to Part1 )
INSERT INTO TBL
VALUES(1, 'rec1', 'TBL_Part1');
INSERT INTO TBL
VALUES(2, 'rec2', 'TBL_Part1');
GO
--Query sub table to verify
SELECT * FROM TBL_Part1
GO
--move the data to table TBL_Part2 by Logical Partition switching technique
UPDATE TBL
SET
PartitionColumn = 'TBL_Part2';
GO
--Query sub table to verify
SELECT * FROM TBL_Part2
Here is how do it with single statement
WITH deleted_rows AS (
DELETE FROM source_table WHERE id = 1
RETURNING *
)
INSERT INTO destination_table
SELECT * FROM deleted_rows;
EXAMPLE:
postgres=# select * from test1 ;
id | name
----+--------
1 | yogesh
2 | Raunak
3 | Varun
(3 rows)
postgres=# select * from test2;
id | name
----+------
(0 rows)
postgres=# WITH deleted_rows AS (
postgres(# DELETE FROM test1 WHERE id = 1
postgres(# RETURNING *
postgres(# )
postgres-# INSERT INTO test2
postgres-# SELECT * FROM deleted_rows;
INSERT 0 1
postgres=# select * from test2;
id | name
----+--------
1 | yogesh
(1 row)
postgres=# select * from test1;
id | name
----+--------
2 | Raunak
3 | Varun
If the two tables use the same ID or have a common UNIQUE key:
1) Insert the selected record in table 2
INSERT INTO table2 SELECT * FROM table1 WHERE (conditions)
2) delete the selected record from table1 if presents in table2
DELETE FROM table1 as A, table2 as B WHERE (A.conditions) AND (A.ID = B.ID)
It will create a table and copy all the data from old table to new table
SELECT * INTO event_log_temp FROM event_log
And you can clear the old table data.
DELETE FROM event_log
For some scenarios, it might be the easiest to script out Table1, rename the existing Table1 to Table2 and run the script to recreate Table1.

How to do INSERT into a table records extracted from another table

I'm trying to write a query that extracts and transforms data from a table and then insert those data into another table. Yes, this is a data warehousing query and I'm doing it in MS Access. So basically I want some query like this:
INSERT INTO Table2(LongIntColumn2, CurrencyColumn2) VALUES
(SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1);
I tried but get a syntax error message.
What would you do if you want to do this?
No "VALUES", no parenthesis:
INSERT INTO Table2(LongIntColumn2, CurrencyColumn2)
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1;
You have two syntax options:
Option 1
CREATE TABLE Table1 (
id int identity(1, 1) not null,
LongIntColumn1 int,
CurrencyColumn money
)
CREATE TABLE Table2 (
id int identity(1, 1) not null,
LongIntColumn2 int,
CurrencyColumn2 money
)
INSERT INTO Table1 VALUES(12, 12.00)
INSERT INTO Table1 VALUES(11, 13.00)
INSERT INTO Table2
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1
Option 2
CREATE TABLE Table1 (
id int identity(1, 1) not null,
LongIntColumn1 int,
CurrencyColumn money
)
INSERT INTO Table1 VALUES(12, 12.00)
INSERT INTO Table1 VALUES(11, 13.00)
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1
INTO Table2
FROM Table1
GROUP BY LongIntColumn1
Bear in mind that Option 2 will create a table with only the columns on the projection (those on the SELECT).
Remove both VALUES and the parenthesis.
INSERT INTO Table2 (LongIntColumn2, CurrencyColumn2)
SELECT LongIntColumn1, Avg(CurrencyColumn) FROM Table1 GROUP BY LongIntColumn1
I believe your problem in this instance is the "values" keyword. You use the "values" keyword when you are inserting only one row of data. For inserting the results of a select, you don't need it.
Also, you really don't need the parentheses around the select statement.
From msdn:
Multiple-record append query:
INSERT INTO target [(field1[, field2[, …]])] [IN externaldatabase]
SELECT [source.]field1[, field2[, …]
FROM tableexpression
Single-record append query:
INSERT INTO target [(field1[, field2[, …]])]
VALUES (value1[, value2[, …])
Remove VALUES from your SQL.
Remove "values" when you're appending a group of rows, and remove the extra parentheses. You can avoid the circular reference by using an alias for avg(CurrencyColumn) (as you did in your example) or by not using an alias at all.
If the column names are the same in both tables, your query would be like this:
INSERT INTO Table2 (LongIntColumn, Junk)
SELECT LongIntColumn, avg(CurrencyColumn) as CurrencyColumn1
FROM Table1
GROUP BY LongIntColumn;
And it would work without an alias:
INSERT INTO Table2 (LongIntColumn, Junk)
SELECT LongIntColumn, avg(CurrencyColumn)
FROM Table1
GROUP BY LongIntColumn;
Well I think the best way would be (will be?) to define 2 recordsets and use them as an intermediate between the 2 tables.
Open both recordsets
Extract the data from the first table (SELECT blablabla)
Update 2nd recordset with data available in the first recordset (either by adding new records or updating existing records
Close both recordsets
This method is particularly interesting if you plan to update tables from different databases (ie each recordset can have its own connection ...)
inserting data form one table to another table in different DATABASE
insert into DocTypeGroup
Select DocGrp_Id,DocGrp_SubId,DocGrp_GroupName,DocGrp_PM,DocGrp_DocType
from Opendatasource( 'SQLOLEDB','Data Source=10.132.20.19;UserID=sa;Password=gchaturthi').dbIPFMCI.dbo.DocTypeGroup
Do you want to insert extraction in an existing table?
If it does not matter then you can try the below query:
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 INTO T1 FROM Table1
GROUP BY LongIntColumn1);
It will create a new table -> T1 with the extracted information