Create a view in sql server using dynamic sql inside - sql-server

I know this sounds weird, but is it possible to have a view that use dynamic SQL to build it? I know the views are compiled so most probably this is not possible. For sure I could do it using an stored procedure instead but I just want to make sure is not possible.
Here I have an example:
declare #Table1 as table (
Id int,
Name nvarchar(50),
Provider nvarchar(50)
)
insert #Table1 values (1, 'John', 'Provider1')
insert #Table1 values (2, 'Peter', 'Provider1')
insert #Table1 values (3, 'Marcus', 'Provider2')
declare #Table2 as table (
Id int,
Info nvarchar(50),
AnotherInfo nvarchar(50)
)
insert #Table2 values (1, 'Expense', '480140')
insert #Table2 values (1, 'Maintenance', '480130')
insert #Table2 values (2, 'Set Up Cost', '480150')
insert #Table2 values (2, 'Something', '480160')
--No columns from Table2
select a.Id, a.Name, a.Provider from #Table1 a left join #Table2 b on a.Id = b.Id
--With columns from Table2
select a.Id, a.Name, a.Provider, b.Info, b.AnotherInfo from #Table1 a left join #Table2 b on a.Id = b.Id
The first select looks like I have repeated data, which is normal because I did the left join, the problem is that for avoiding that I need to perform a distinct and this is what I don't want to do. My example is short but I have much more columns and table is quite big.

Related

How to fix this error 'The column 'DistrictID' was specified multiple times for 'piv'

I want to show the inspector name, inspector post, district and project with inspection done by the inspector according to months for which i'm using pivot but i'm getting
"The column 'DistrictID' was specified multiple times for 'piv'." this error...
Please help me to get over this error
Declare #SQLQuery nvarchar(MAX)
If(OBJECT_ID('tempdb..#TBL1') Is Not Null)
Begin
Drop Table #TBL1
End
CREATE TABLE #TBL1
(
ID int,
InspPost nvarchar (MAX),
InspPostHin nvarchar(MAX)
)
SET #SQLQuery ='INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (1, N''Child Development Project Officer'', N''??? ????? ???????? ?????????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (2, N''Lady Superviser'', N''????? ????????????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (3, N''Other'', N''???? ?????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (4, N''District Program Officer'', N''???? ????????? ?????????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (5, N''J.P.C/State Level Officer'',N''??.??.??../???? ???????? ????? ?????? ???????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (6, N''S.P.M.U/Technical Consultant'', N''??.??..??.??. - ?????? ???????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (7, N''District Coordinator'', N''???? ???????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (8, N''Project Coordinator'', N''?????? ???????'')
INSERT into #TBL1 ([ID], [InspPost], [InspPostHin]) VALUES (9, N''Swasth Bharat Prerak'', N''?????? ???? ??????'')'
exec (#SQLQuery)
select * from
(
select Districtmaster.DistrictID,ProjectMaster.ProjectID,Districtmaster.DistrictNameHn,ProjectMaster.ProjectNameHn from Districtmaster Districtmaster
inner join ProjectMaster ProjectMaster on Districtmaster.DistrictID=ProjectMaster.DistID
) a1
inner join
(
select Supervision_Checklist.ID,Supervision_Checklist.Inspector_Name,
Supervision_Checklist.DistrictID,Supervision_Checklist.ProjectID,
Supervision_Checklist.Inspector_Type,(#TBL1.InspPost) as inptype ,Supervision_Checklist.Month
from Supervision_Checklist Supervision_Checklist
inner join #TBL1 #TBL1
on Supervision_Checklist.Inspector_Type=#TBL1.ID
) src on a1.DistrictID=src.DistrictID and a1.ProjectID=src.ProjectID
pivot (count(id) for Month in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) piv
i want result as following...
enter image description here
A PIVOT effectively performs a GROUP BY on all columns which are currently in the result set and which aren't mentioned in the pivot.
If you've done a bit of joining, it's highly likely (as here) that you'll end up with multiple columns of the same name (DistrictID). Even though we know that both DistrictID values are equal on every row, the optimizer doesn't, and generates this error.
What we need to do is project away the columns that we don't want included in this grouping operation. But there's no convenient way to express this "inline". We need to have a SELECT clause and we need the PIVOT to be on the "other side" of that SELECT clause.
Typically, we'd do this using a subquery or CTE:
;With AllResults as (
select
id,
month,
/* We cannot use * here. We need only those columns needed by the pivot
or which should appear in the final result */
from
(
select Districtmaster.DistrictID,ProjectMaster.ProjectID,Districtmaster.DistrictNameHn,ProjectMaster.ProjectNameHn from Districtmaster Districtmaster
inner join ProjectMaster ProjectMaster on Districtmaster.DistrictID=ProjectMaster.DistID
) a1
inner join
(
select Supervision_Checklist.ID,Supervision_Checklist.Inspector_Name,
Supervision_Checklist.DistrictID,Supervision_Checklist.ProjectID,
Supervision_Checklist.Inspector_Type,(#TBL1.InspPost) as inptype ,Supervision_Checklist.Month
from Supervision_Checklist Supervision_Checklist
inner join #TBL1 #TBL1
on Supervision_Checklist.Inspector_Type=#TBL1.ID
) src on a1.DistrictID=src.DistrictID and a1.ProjectID=src.ProjectID
)
select *
from AllResults
pivot (count(id) for Month in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) piv

How to update table when rows of one table are different from the other

I have a table table1 and a temporary table temp2. Temp2 contains updated values which i want to update in table1. So, for any rows that are different i want to update the values from Temp2 to table 1. I tried something like this but its not working.
update Role_Master set Role_Desc=Role_Descc , Role_Version_Number =Role_Version_Number+1,Role_Dept=Role_Deptt,Role_All_Clients=Role_All_Clientss,
Role_Admin=Role_Adminn,Role_Super_Admin=Role_Super_Adminn,Role_Modified_Date = GETDATE(),Role_Modified_By = 'T6086' FROM #TEMP1 where Role_ID in
(SELECT #TEMP1.Role_IDD FROM #TEMP1 LEFT JOIN Role_Master ON (#TEMP1.Role_Descc = Role_Master.Role_Desc and #Temp1.Role_Deptt=Role_Master.Role_Dept)
WHERE Role_Master.Role_Desc is null and Role_Master.Role_Dept IS NULL)
hard to help you without knowing the schema of the two tables ... but it should be possible to join the two tables and decide by a where condition which rows to update ... check out this simple example ... maybe it helps
create table #temp1 (id int, val nvarchar(100))
create table #temp2 (id int, val nvarchar(100))
insert into #temp1 (id, val) values (1, 'eins')
insert into #temp1 (id, val) values (2, 'eins')
insert into #temp1 (id, val) values (3, 'eins')
insert into #temp2 (id, val) values (1, 'zwei')
insert into #temp2 (id, val) values (2, 'eins')
insert into #temp2 (id, val) values (3, 'eins')
update #temp1 set #temp1.val = b.val
from #temp1 a join #temp2 b on a.id = b.id
where a.val <> b.val
select ##rowcount -- returns 1 because 1 row was updated
select * from #temp1

Left join results in extra records

This is a basic left join problem and I have read many articles explaining what is going on but somehow the resolution is not clicking in my head. My left table has unique records. My right table has several records for each record in the left.
In the articles I have been reading this is often explained as left table has customers and right table has orders. That is very similar but not exactly what I am facing.
In my situation the left table has unique records and the right has repetitive data to be migrated into db the left table is in. So I am trying to write a query that will join on the key shared by both but I only need one record from the right. The results I am getting of course have multiple records since the single left matches multiple times on the right.
I am thinking I need to add some sort of filtering such as Top(1) but still reading / learning and wanted to get feedback / direction from the brainiacs on this list.
Here is a simple schema of what I am working with:
DECLARE #Customer TABLE
(
Id int,
Name varchar(50),
email varchar(50)
)
INSERT #Customer VALUES(1, 'Frodo', 'frodo#middleearth.org')
INSERT #Customer VALUES(2, 'Bilbo', 'Bilbo#middleearth.org')
INSERT #Customer VALUES(3, 'Galadriel', 'Galadriel#middleearth.org')
INSERT #Customer VALUES(4, 'Arwen', 'Arwen#middleearth.org')
INSERT #Customer VALUES(5, 'Gandalf', 'Gandalf#middleearth.org')
DECLARE #CustomerJobs TABLE
(
Id int,
email varchar(50),
jobname varchar(50)
)
INSERT #CustomerJobs VALUES(1, 'frodo#middleearth.org', 'RingBearer')
INSERT #CustomerJobs VALUES(2, 'frodo#middleearth.org', 'RingBearer')
INSERT #CustomerJobs VALUES(3, 'frodo#middleearth.org', 'RingBearer')
INSERT #CustomerJobs VALUES(4, 'frodo#middleearth.org', 'RingBearer')
INSERT #CustomerJobs VALUES(5, 'frodo#middleearth.org', 'RingBearer')
INSERT #CustomerJobs VALUES(6, 'Bilbo#middleearth.org', 'Burglar')
INSERT #CustomerJobs VALUES(7, 'Bilbo#middleearth.org', 'Burglar')
INSERT #CustomerJobs VALUES(8, 'Bilbo#middleearth.org', 'Burglar')
INSERT #CustomerJobs VALUES(9, 'Galadriel#middleearth.org', 'MindReader')
INSERT #CustomerJobs VALUES(10, 'Arwen#middleearth.org', 'Evenstar')
INSERT #CustomerJobs VALUES(10, 'Arwen#middleearth.org', 'Evenstar')
INSERT #CustomerJobs VALUES(11, 'Gandalf#middleearth.org', 'WhiteWizard')
INSERT #CustomerJobs VALUES(12, 'Gandalf#middleearth.org', 'WhiteWizard')
SELECT
Cust.Name,
Cust.email,
CJobs.jobname
FROM
#Customer Cust
LEFT JOIN #CustomerJobs CJobs ON
Cjobs.email = Cust.email
I'm toying with row_number over partition() as maybe I should be joining to a cte with the row_number over partition instead of the table itself???
One other constraint I have is I can't delete the duplicates from the right table.
So again my apologies for the simplistic question and thank you for the help.
Instead of using a left join, use an outer apply... you can then use the top clause to limit the rows returned...
select
Cust.Name
, Cust.email
, CJobs.jobname
from #Customer Cust
outer apply (
select top 1 *
from #CustomerJobs CJobs
where Cjobs.email = Cust.email
) cjobs;
You have to come up with some artificial method of reducing the second table to one row per email. For example:
SELECT
Cust.Name,
Cust.ID,
Cust.email,
CJobs.jobname
FROM
#Customer Cust
LEFT JOIN
(select min(id) as id,email, jobname
from
#CustomerJobs
group by email, jobname) as CJobs ON
Cjobs.email = Cust.email
But that's pretty much random. Is there a way to determine which row from your CustomerJobs table is the "right" one?
SELECT DISTINCT
Cust.Name,
Cust.email,
CJobs.jobname
FROM
#Customer Cust
LEFT JOIN #CustomerJobs CJobs ON
Cjobs.email = Cust.email
The additional of the DISTINCT keyword should get you what you want.
This will work:
SELECT
Cust.Name,
Cust.ID,
Cust.email,
CJobs.jobname
FROM #Customer Cust
LEFT JOIN
(SELECT DISTINCT email, jobname
FROM #CustomerJobs) C2 ON C2.email = C.email

How do I find records out of order - SQL?

Let's say I have a table with an ID Identity column, some data, and a datestamp. Like this:
1 data 5/1/2013 12:30
2 data 5/2/2013 15:32
3 data 5/2/2013 16:45
4 data 5/3/2013 9:32
5 data 5/5/2013 8:21
6 data 5/4/2013 9:36
7 data 5/6/2013 11:42
How do I write a query that will show me the one record that is timestamped 5/4? The table has millions of records. I've done some searching, but I don't know what to call what I'm searching for. :/
declare #t table(id int, bla char(4), timestamp datetime)
insert #t values
(1,'data','5/1/2013 12:30'),
(2,'data','5/2/2013 15:32'),
(3,'data','5/2/2013 16:45'),
(4,'data','5/3/2013 9:32'),
(5,'data','5/5/2013 8:21'),
(6,'data','5/4/2013 9:36'),
(7,'data','5/6/2013 11:42')
select timestamp
from
(
select rn1 = row_number() over (order by id),
rn2 = row_number() over (order by timestamp), timestamp
from #t
) a
where rn1 not in (rn2, rn2-1)
in 2008 r2, this would be a way
DECLARE #Table AS TABLE
(id INT , ladate DATETIME)
INSERT INTO #Table VALUES (1, '2013-05-01')
INSERT INTO #Table VALUES (2, '2013-05-02')
INSERT INTO #Table VALUES (3, '2013-05-03')
INSERT INTO #Table VALUES (4, '2013-05-05')
INSERT INTO #Table VALUES (5, '2013-05-04')
INSERT INTO #Table VALUES (6, '2013-05-06')
INSERT INTO #Table VALUES (7, '2013-05-07')
INSERT INTO #Table VALUES (8, '2013-05-08')
--I added the records in the sort order but if not just make sure you are sorted in the query
SELECT t2.ladate FROM #Table T1
INNER JOIN #Table T2 ON T1.Id = T2.Id + 1
INNER JOIN #Table t3 ON t2.id = t3.id + 1
WHERE t3.ladate < t2.ladate AND t2.ladate > t1.ladate
-- I made the assumption that your Id are all there, 1,2,3,4,5.... none missing... if there are rownumbers missing, you can use row_number()

Deleting 'equivalent' data from two tables

I need to perform the following pseudo logic in a SQL Server 2012 procedure, based around a table variable and a table declared as such:
DECLARE #tmp TABLE
(
ID int IDENTITY(1,1),
UserID int NOT NULL,
SgsID int NOT NULL
)
CREATE TABLE #Table1
(
ID int IDENTITY(1,1),
UserID int NOT NULL,
SgsID int NOT NULL
)
For each row of data in table variable #tmp
Delete rows from Table1 where UserID/SgsID combinations match UserID/SgsID in Table1
Delete those UserID/SgsID combinations from #tmp that have been deleted from Table1
I've been researching different approaches, such as using OUTPUT INTO and INTERSECT, but cannot write a query that deletes across two tables (in fact I don't think it is even possible).
I have achieved the above steps by using the following code, however, I was wondering if any T-SQL pro's may be able to suggest a more succinct/efficient approach?
See SQLFiddle for online version
CREATE TABLE #Table1
(
ID int IDENTITY(1,1),
UserID int NOT NULL,
SgsID int NOT NULL
)
INSERT INTO #Table1 (UserID, SgsID) VALUES (5, 99)
INSERT INTO #Table1 (UserID, SgsID) VALUES (10, 89)
INSERT INTO #Table1 (UserID, SgsID) VALUES (150, 79)
INSERT INTO #Table1 (UserID, SgsID) VALUES (200, 69)
INSERT INTO #Table1 (UserID, SgsID) VALUES (250, 59)
SELECT * FROM #Table1
DECLARE #tmp TABLE
(
ID int IDENTITY(1,1),
UserID int NOT NULL,
SgsID int NOT NULL
)
INSERT INTO #tmp (UserID, SgsID) VALUES (150, 79)
INSERT INTO #tmp (UserID, SgsID) VALUES (200, 69)
INSERT INTO #tmp (UserID, SgsID) VALUES (250, 59)
INSERT INTO #tmp (UserID, SgsID) VALUES (999, 49)
SELECT * FROM #tmp
DECLARE #tbl_commonRows TABLE (UserID int, SgsID int)
INSERT INTO #tbl_commonRows
(
UserID,
SgsID
)
SELECT
UserID,
SgsID
FROM
#Table1
INTERSECT
SELECT
UserID,
SgsID
FROM
#tmp
DELETE FROM
#Table1
WHERE
(ID IN (
SELECT
ID
FROM
#Table1 t1 INNER JOIN
#tbl_commonRows c ON c.UserID = t1.UserID AND c.SgsID = t1.SgsID))
DELETE FROM
#tmp
WHERE
(ID IN (
SELECT
ID
FROM
#tmp t2 INNER JOIN
#tbl_commonrows c ON c.UserID = t2.UserID AND c.SgsID = t2.SgsID))
SELECT * FROM #Table1
SELECT * FROM #tmp
DROP TABLE #Table1
Here's solution:
DECLARE #tmp_ids TABLE (
id1 INT,
id2 INT
)
INSERT INTO #tmp_ids (id1, id2)
SELECT
t1.id,
t2.id
FROM Table1 t1
INNER JOIN tmp t2
on (t1.UserID = t2.UserID AND t1.SgsID = t2.SgsID)
DELETE FROM Table1
WHERE id IN (SELECT id1 FROM #tmp_ids)
DELETE FROM tmp
WHERE id IN (SELECT id2 FROM #tmp_ids)
Keep in mind - i created physical tables tmp and Table1
You can take advantage of the fact that the OUTPUT command can take more than INSERTED and DELETED columns for deletes (but not inserts, sadly):
DECLARE #output TABLE (id int)
DELETE FROM tbl
OUTPUT tmp.ID INTO #output(id)
FROM #Table1 tbl
JOIN #tmp tmp
ON tbl.UserID = tmp.UserID
AND tbl.SgsID = tmp.SgsID
DELETE FROM tmp
FROM #tmp tmp
JOIN #Output outp ON tmp.id = outp.id
Have you looked into using MERGE for this? Might be another option, and the syntax is nice and easy to follow.
MERGE (Transact-SQL)

Resources