Related
I have a table with the following information:
CREATE TABLE A (
ID int,
start_date varchar(255),
effdate varchar(255),
enddate varchar(255),
lead_effdate varchar(255),
value varchar(255),
source varchar(255),
lead_source varchar(255)
);
INSERT INTO A
VALUES (1,"12/01/2013","12/01/2013","30/07/2014","31/07/2014",4,"REM","REM"),
(1,"31/07/2014","31/07/2014","04/09/2014","12/09/2014",4,"REM","REM"),
(1,"12/09/2014","12/09/2014","12/04/2015","13/04/2015",4,"REM","REM"),
(1,"13/04/2015","13/04/2015","01/01/2016","02/01/2016",4,"REM","REM"),
(1,"02/01/2016","02/01/2016","11/03/2016","13/03/2016",4,"REM","REM"),
(1,"13/03/2016","13/03/2016","22/04/2017","10/07/2016",4,"REM","GS"),
(1,"10/07/2016","10/07/2016",null,"23/04/2017",4,"GS","REM"),
(1,"23/04/2017","23/04/2017","05/05/2018","06/05/2018",4,"REM","REM"),
(1,"06/05/2018","06/05/2018","09/11/2019","10/11/2019",4,"REM","REM"),
(1,"10/11/2019","10/11/2019",null,null,4,"REM",null);
select * from A
order by start_date
I would like to delete all rows from source = GS to the lowest row in the table. The order is given by start_date as you can see.
I tried to use a row_number() over(partition by... to create negative and positive values around GS, but I couldn't figure this index. How would you solve it?
If by "to the bottom" you mean "a larger id" then you can use join in the delete:
delete a
from a join
(select max(id) as gs_id
from a
where source = 'GS'
) aa
on a.id > aa.gs_id;
You want to select all rows with a date equal to or newer than a row with source = 'GS'. As there can be multiple rows with source = 'GS' you must decide for one row. Probably the first or the last.
delete from a where start_date >= (select min(start_date) from a where source = 'GS');
I am looking for select query with dynamic column names that can be derived from another table. Below the sample data and query I am looking to get.
create table mapping_tmp (
string_number varchar,
mapping_name varchar
)
create table fact_tmp (
product varchar,
product_family varchar,
string1 varchar,
string2 varchar,
string3 varchar,
string4 varchar,
string5 varchar
)
insert into mapping_tmp values ('string1','commodity');
insert into mapping_tmp values ('string2','real commodity');
insert into mapping_tmp values ('string3','country');
insert into mapping_tmp values ('string4','region');
insert into mapping_tmp values ('string5','area');
insert into fact_tmp values ('P1','PF1','ABC1','DEF1','GHI1','JKL1','MNO1');
insert into fact_tmp values ('P2','PF2','ABC2','DEF2','GHI2','JKL2','MNO2');
insert into fact_tmp values ('P3','PF3','ABC3','DEF3','GHI3','JKL3','MNO3');
insert into fact_tmp values ('P4','PF4','ABC4','DEF4','GHI4','JKL4','MNO4');
insert into fact_tmp values ('P5','PF5','ABC5','DEF5','GHI5','JKL5','MNO5');
insert into fact_tmp values ('P6','PF6','ABC6','DEF6','GHI6','JKL6','MNO6');
Expected output, select fields should be taken from mapping_tmp and those fields data should be displayed in select result.
select product,
(select string_number from mapping_tmp where mapping_name = 'country') as country,
(select string_number from mapping_tmp where mapping_name = 'area') as area
from fact_tmp;
The actual query is
select product, string3 as country, string5 as area from fact_tmp;
and the output:
product country area
1 P1 GHI1 MNO1
2 P2 GHI2 MNO2
3 P3 GHI3 MNO3
4 P4 GHI4 MNO4
5 P5 GHI5 MNO5
6 P6 GHI6 MNO6
I am looking for simple sql query, I cannot use stored procedure or function in application.
How to insert into table 2 all field values of a row from table A, where all values in a column A in table 1 that satisfy a condition on column B of table 1 ,but do not exist in table 2.How to frame a query using not exists?
I tried this:
INSERT INTO Teachermast (
teacher_code,
teacher_name,
designation,
dept_code,
contact_no,
email,
address,
dob,
PASSWORD
)
SELECT
userId,
username,
designation,
dept,
contact_no,
email,
address,
dob,
PASSWORD
FROM
UserMast
WHERE NOT EXISTS
(SELECT
userId
FROM
UserMast
WHERE usertype = '3')
but this doesnt seem to work.
Kindly help.
You could do a MERGE
create table users
(
userId varchar(50),
username varchar(50),
usertype int,
password varchar(50),
contact_no varchar(50),
email varchar(50),
faxno varchar(50),
address varchar(50),
created_date date,
updated_date date,
status varchar(50),
gender varchar(50),
dob date,
lasttimelogin datetime,
login_time datetime,
logoutt_time datetime,
designation varchar(50),
dept varchar(50),
email_pass varchar(50)
)
insert into users values('T0003','Ankita',3,'12345','9858585245','anki#gmail.com','201','l block noid sec 25',NULL,NULL,NULL,'Female','11/09/1990',NULL,NULL,NULL,'Teacher','EC',NULL);
insert into users values('T0004','Ribha',3,'12345','9512365423','sharma#gmail.com',NULL,'221 dwarka sec 10',NULL,NULL,NULL,'Female','12/02/1989',NULL,NULL,NULL,'Teacher','EC',NULL);
create table teachers
(
teacher_code varchar(50),
teacher_name varchar(50),
designation varchar(50),
dept_code varchar(50),
contact_no varchar(50),
email varchar(50),
address varchar(50),
dob date,
password varchar(50)
)
insert into teachers values('T0002','Tanvi','Teacher','CS','9632569856','tan123#gmail.com','298 mayur vihar ph 1','29/06/1990','12345');
insert into teachers values('T0003','Ankita','Teacher','EC','9858585245','anki#gmail.com','201 l block noida sec 25','11/09/1990','12345');
merge teachers as target
using (select userid, username, designation, dept, contact_no, email, address, dob, password from users where usertype = 3)
as source(userid, username, designation, dept, contact_no, email, address, dob, password)
on target.teacher_code = source.userid
when not matched by target then
insert (teacher_code, teacher_name, designation, dept_code, contact_no, email, address, dob, password)
values (source.userid, source.username, source.designation, source.dept, source.contact_no, source.email, source.address, source.dob, source.password);
select * from teachers
However, I think there are issues with your database design. With your current model, you could have, for example, a different address (or password!) for Ankita in table1 compared to table2. And if you change any of that information you would have to change it in both places.
Could you, for example, just insert everyone into "users" and have "teachers" be a view
select {columns} from users where usertype = 3
Please try this query
SELECT
t.userId,
t.username,
t.designation,
t.dept,
t.contact_no,
t.email,
t.address,
t.dob,
t.PASSWORD
FROM Teachermast as t
LEFT join UserMast as u on t.userId = u.teacher_code
WHERE t.usertype = '3' and u.teacher_code is null
I have this table
CREATE TABLE Repondant
matricule CHAR(8) NOT NULL, -- Roll
name VARCHAR(64) NOT NULL,
roll VARCHAR(64) NOT NULL,
email VARCHAR(80) NOT NULL,
CONSTRAINT Repondant_cc0 PRIMARY KEY (matricule),
CONSTRAINT Repondant_cc1 UNIQUE (courriel),
CONSTRAINT Repondant_matricule CHECK (matricule SIMILAR TO '[0-9]{8}'),
CONSTRAINT Repondant_nom CHECK (LENGTH(nom) > 0),
CONSTRAINT Repondant_prenom CHECK (LENGTH(prenom) > 0),
CONSTRAINT Repondant_courriel CHECK (
LOWER(courriel) SIMILAR TO
'[^][()<>:;#\,."[:space:][:cntrl:]]+(\.[^][()<>:;#\,."[:space:][:cntrl:]]+)*\#hotmail.com'
)
);
I want to make a request that gives me the name,lastname,email and roll for all the homonyms in the table(same name and same firstname)
I tried
(SELECT name,lastname,role,email
FROM Repondant
Where name = (SELECT name FROM Repondant GROUP BY nom HAVING COUNT(*)>1) AND
lastname = (SELECT lastname FROM Repondant GROUP BY prenom HAVING COUNT(*)>1)
Problem is, it doesnt give the homonyms, it only gives the persons that have their name and their Lastname at least 1 time in the table, but not alway together.
How should I find the homonyms ?
You can build a array to check the occurrence of more than a value.
For example this is a variant with a subquery:
SELECT * from repondant
WHERE (name,lastname) in
(
SELECT name,lastname
FROM repondant
GROUP BY name, lastname
HAVING count(array[name,lastname]) > 1
);
I am creating a stored procedure to do a search through a table. I have many different search fields, all of which are optional. Is there a way to create a stored procedure that will handle this? Let's say I have a table with four fields: ID, FirstName, LastName and Title. I could do something like this:
CREATE PROCEDURE spDoSearch
#FirstName varchar(25) = null,
#LastName varchar(25) = null,
#Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
FirstName = ISNULL(#FirstName, FirstName) AND
LastName = ISNULL(#LastName, LastName) AND
Title = ISNULL(#Title, Title)
END
This sort of works. However it ignores records where FirstName, LastName or Title are NULL. If Title is not specified in the search parameters I want to include records where Title is NULL - same for FirstName and LastName. I know I could probably do this with dynamic SQL but I would like to avoid that.
Dynamically changing searches based on the given parameters is a complicated subject and doing it one way over another, even with only a very slight difference, can have massive performance implications. The key is to use an index, ignore compact code, ignore worrying about repeating code, you must make a good query execution plan (use an index).
Read this and consider all the methods. Your best method will depend on your parameters, your data, your schema, and your actual usage:
Dynamic Search Conditions in T-SQL by by Erland Sommarskog
The Curse and Blessings of Dynamic SQL by Erland Sommarskog
If you have the proper SQL Server 2008 version (SQL 2008 SP1 CU5 (10.0.2746) and later), you can use this little trick to actually use an index:
Add OPTION (RECOMPILE) onto your query, see Erland's article, and SQL Server will resolve the OR from within (#LastName IS NULL OR LastName= #LastName) before the query plan is created based on the runtime values of the local variables, and an index can be used.
This will work for any SQL Server version (return proper results), but only include the OPTION(RECOMPILE) if you are on SQL 2008 SP1 CU5 (10.0.2746) and later. The OPTION(RECOMPILE) will recompile your query, only the verison listed will recompile it based on the current run time values of the local variables, which will give you the best performance. If not on that version of SQL Server 2008, just leave that line off.
CREATE PROCEDURE spDoSearch
#FirstName varchar(25) = null,
#LastName varchar(25) = null,
#Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
(#FirstName IS NULL OR (FirstName = #FirstName))
AND (#LastName IS NULL OR (LastName = #LastName ))
AND (#Title IS NULL OR (Title = #Title ))
OPTION (RECOMPILE) ---<<<<use if on for SQL 2008 SP1 CU5 (10.0.2746) and later
END
The answer from #KM is good as far as it goes but fails to fully follow up on one of his early bits of advice;
..., ignore compact code, ignore worrying about repeating code, ...
If you are looking to achieve the best performance then you should write a bespoke query for each possible combination of optional criteria. This might sound extreme, and if you have a lot of optional criteria then it might be, but performance is often a trade-off between effort and results. In practice, there might be a common set of parameter combinations that can be targeted with bespoke queries, then a generic query (as per the other answers) for all other combinations.
CREATE PROCEDURE spDoSearch
#FirstName varchar(25) = null,
#LastName varchar(25) = null,
#Title varchar(25) = null
AS
BEGIN
IF (#FirstName IS NOT NULL AND #LastName IS NULL AND #Title IS NULL)
-- Search by first name only
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
FirstName = #FirstName
ELSE IF (#FirstName IS NULL AND #LastName IS NOT NULL AND #Title IS NULL)
-- Search by last name only
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
LastName = #LastName
ELSE IF (#FirstName IS NULL AND #LastName IS NULL AND #Title IS NOT NULL)
-- Search by title only
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
Title = #Title
ELSE IF (#FirstName IS NOT NULL AND #LastName IS NOT NULL AND #Title IS NULL)
-- Search by first and last name
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
FirstName = #FirstName
AND LastName = #LastName
ELSE
-- Search by any other combination
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
(#FirstName IS NULL OR (FirstName = #FirstName))
AND (#LastName IS NULL OR (LastName = #LastName ))
AND (#Title IS NULL OR (Title = #Title ))
END
The advantage of this approach is that in the common cases handled by bespoke queries the query is as efficient as it can be - there's no impact by the unsupplied criteria. Also, indexes and other performance enhancements can be targeted at specific bespoke queries rather than trying to satisfy all possible situations.
You can do in the following case,
CREATE PROCEDURE spDoSearch
#FirstName varchar(25) = null,
#LastName varchar(25) = null,
#Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
(#FirstName IS NULL OR FirstName = #FirstName) AND
(#LastNameName IS NULL OR LastName = #LastName) AND
(#Title IS NULL OR Title = #Title)
END
however depend on data sometimes better create dynamic query and execute them.
Five years late to the party.
It is mentioned in the provided links of the accepted answer, but I think it deserves an explicit answer on SO - dynamically building the query based on provided parameters. E.g.:
Setup
-- drop table Person
create table Person
(
PersonId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_Person PRIMARY KEY,
FirstName NVARCHAR(64) NOT NULL,
LastName NVARCHAR(64) NOT NULL,
Title NVARCHAR(64) NULL
)
GO
INSERT INTO Person (FirstName, LastName, Title)
VALUES ('Dick', 'Ormsby', 'Mr'), ('Serena', 'Kroeger', 'Ms'),
('Marina', 'Losoya', 'Mrs'), ('Shakita', 'Grate', 'Ms'),
('Bethann', 'Zellner', 'Ms'), ('Dexter', 'Shaw', 'Mr'),
('Zona', 'Halligan', 'Ms'), ('Fiona', 'Cassity', 'Ms'),
('Sherron', 'Janowski', 'Ms'), ('Melinda', 'Cormier', 'Ms')
GO
Procedure
ALTER PROCEDURE spDoSearch
#FirstName varchar(64) = null,
#LastName varchar(64) = null,
#Title varchar(64) = null,
#TopCount INT = 100
AS
BEGIN
DECLARE #SQL NVARCHAR(4000) = '
SELECT TOP ' + CAST(#TopCount AS VARCHAR) + ' *
FROM Person
WHERE 1 = 1'
PRINT #SQL
IF (#FirstName IS NOT NULL) SET #SQL = #SQL + ' AND FirstName = #FirstName'
IF (#LastName IS NOT NULL) SET #SQL = #SQL + ' AND FirstName = #LastName'
IF (#Title IS NOT NULL) SET #SQL = #SQL + ' AND Title = #Title'
EXEC sp_executesql #SQL, N'#TopCount INT, #FirstName varchar(25), #LastName varchar(25), #Title varchar(64)',
#TopCount, #FirstName, #LastName, #Title
END
GO
Usage
exec spDoSearch #TopCount = 3
exec spDoSearch #FirstName = 'Dick'
Pros:
easy to write and understand
flexibility - easily generate the query for trickier filterings (e.g. dynamic TOP)
Cons:
possible performance problems depending on provided parameters, indexes and data volume
Not direct answer, but related to the problem aka the big picture
Usually, these filtering stored procedures do not float around, but are being called from some service layer. This leaves the option of moving away business logic (filtering) from SQL to service layer.
One example is using LINQ2SQL to generate the query based on provided filters:
public IList<SomeServiceModel> GetServiceModels(CustomFilter filters)
{
var query = DataAccess.SomeRepository.AllNoTracking;
// partial and insensitive search
if (!string.IsNullOrWhiteSpace(filters.SomeName))
query = query.Where(item => item.SomeName.IndexOf(filters.SomeName, StringComparison.OrdinalIgnoreCase) != -1);
// filter by multiple selection
if ((filters.CreatedByList?.Count ?? 0) > 0)
query = query.Where(item => filters.CreatedByList.Contains(item.CreatedById));
if (filters.EnabledOnly)
query = query.Where(item => item.IsEnabled);
var modelList = query.ToList();
var serviceModelList = MappingService.MapEx<SomeDataModel, SomeServiceModel>(modelList);
return serviceModelList;
}
Pros:
dynamically generated query based on provided filters. No parameter sniffing or recompile hints needed
somewhat easier to write for those in the OOP world
typically performance friendly, since "simple" queries will be issued (appropriate indexes are still needed though)
Cons:
LINQ2QL limitations may be reached and forcing a downgrade to LINQ2Objects or going back to pure SQL solution depending on the case
careless writing of LINQ might generate awful queries (or many queries, if navigation properties loaded)
Extend your WHERE condition:
WHERE
(FirstName = ISNULL(#FirstName, FirstName)
OR COALESCE(#FirstName, FirstName, '') = '')
AND (LastName = ISNULL(#LastName, LastName)
OR COALESCE(#LastName, LastName, '') = '')
AND (Title = ISNULL(#Title, Title)
OR COALESCE(#Title, Title, '') = '')
i. e. combine different cases with boolean conditions.
This also works:
...
WHERE
(FirstName IS NULL OR FirstName = ISNULL(#FirstName, FirstName)) AND
(LastName IS NULL OR LastName = ISNULL(#LastName, LastName)) AND
(Title IS NULL OR Title = ISNULL(#Title, Title))