how to get table from first table when data is not there in second table - sql

i have requirement where i need to show data of both tables when both the ID's are same.when id is present in first table and not there in second table i need to show data from first table
CREATE TABLE [dbo].[TEST](
[ID] [int] NULL,
[Name] [varchar](10) NULL,
[Status] [char](1) NULL,
[CreatedDate] [datetime] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Test_History](
[ID] [int] NULL,
[Name] [varchar](10) NULL,
[Status] [char](1) NULL,
[CreatedDate] [datetime] NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Test_History] Script Date: 06/19/2015 19:01:49 ******/
INSERT [dbo].[Test_History] ([ID], [Name], [Status], [CreatedDate]) VALUES (1, N'Mohan', N'A', CAST(0x0000A4BC01347E88 AS DateTime))
INSERT [dbo].[Test_History] ([ID], [Name], [Status], [CreatedDate]) VALUES (1, N'Mohan', N'I', CAST(0x0000A4BC0134A390 AS DateTime))
INSERT [dbo].[Test_History] ([ID], [Name], [Status], [CreatedDate]) VALUES (2, N'Rohan', N'A', CAST(0x0000A4BC01391FCC AS DateTime))
/****** Object: Table [dbo].[TEST] Script Date: 06/19/2015 19:01:49 ******/
INSERT [dbo].[TEST] ([ID], [Name], [Status], [CreatedDate]) VALUES (2, N'Rohan', N'I', CAST(0x0000A4BC0138D584 AS DateTime))
INSERT [dbo].[TEST] ([ID], [Name], [Status], [CreatedDate]) VALUES (1, N'Mohan', N'A', CAST(0x0000A4BC013072DC AS DateTime))
INSERT [dbo].[TEST] ([ID], [Name], [Status], [CreatedDate]) VALUES (3, N'Raj', N'A', CAST(0x0000A4BC0138DED7 AS DateTime))
INSERT [dbo].[TEST] ([ID], [Name], [Status], [CreatedDate]) VALUES (4, N'Krishna', N'A', CAST(0x0000A4BC0138EE31 AS DateTime))
so far i have tried my query to achieve the result
select T.ID,COALESCE(T.ID,TT.ID),T.Name,COALESCE(T.Name,TT.Name),T.status,COALESCE(T.status,TT.status)
from Test T LEFT JOIN (Select TOP 1 ID,MIN(Name)name,Status from Test_History
GROUP BY ID,status
)TT
ON T.ID = TT.ID
where T.ID = 3
Id = 1 and 2 present show i will get data from both tables
Id = 3 and 4 not present in the table
so using coalesce i will get the data
from first table and show in 2nd table column also
but is there any other way like both tables are same structure
i'm thinking of
Declare #tablename varchar(10)
IF EXISTS (SELECT 1 from TESt where id = #id)
IF COunt there in both tables
SET #tablename = Test
ELSE
SET #tablename = Test_history
select * from #tablename where id = #ID
can i get any solution like this

You can use EXCEPT.
Here is an example:
SELECT a,b
FROM (
VALUES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10)
) AS MyTable(a, b)
EXCEPT
SELECT a,b
FROM (
VALUES (1, 2), (7, 8), (9, 10)
) AS MyTable(a, b);
This will return all rows of the upper statement, which are not in the second statement.

First: Thanks for the excellent setup for the data related to the question!
If your real question was if table variables can be used as described in your question, the answer is no; or more accurately that its not worth it.
Not recommended:
declare #TableName TABLE (
[ID] [int] NULL,
[Name] [varchar](10) NULL,
[Status] [char](1) NULL,
[CreatedDate] [datetime] NULL)
IF EXISTS (SELECT 1 from TESt where id = #id)
INSERT INTO #TableName SELECT * FROM dbo.TEST WHERE ID = #ID
ELSE INSERT INTO #TableName SELECT * FROM dbo.[Test_History] WHERE ID = #ID
select * from #tablename where id = #ID
Here's the solution I prefer:
DECLARE #ID INT = 3;
SELECT * FROM [dbo].[TEST] ss WHERE ss.id = #id
UNION ALL SELECT * FROM [dbo].[Test_History] th WHERE th.id = #id
and not exists ( SELECT * FROM [dbo].[TEST] ss WHERE ss.id = #id);
UNION ALL performs surprisingly well - don't forget the ALL keyword, and I am assuming that ID is a PK or AK.

If I'm understanding correctly and you want to display all records that match between the two tables and only records from first table when the id does not exist in the second in the same result set, then all you need is a simple left join:
SELECT *
FROM dbo.test t
LEFT OUTER JOIN Test_History th
ON t.id = th.id
WHERE t.id = #id

Related

MS SQL Server 2008 query - doesn't get proper send and received message count

SELECT DISTINCT
U.UserId as 'Id',
U.FullName as 'Name',
(SELECT COUNT(*) FROM [Conversation]
WHERE FromUserId = 'user1' AND ToUserId = U.UserId) 'SentCount',
(SELECT COUNT(*) FROM [Conversation]
WHERE ToUserId = 'user1' AND FromUserId = U.UserId) 'ReceivedCount'
FROM
[Conversation] C
INNER JOIN
[User] U ON U.UserId = C.FromUserId
WHERE
C.ToUserId = 'user1'
Query returns a result but it doesn't include some of the rows. Conversation table contains the same FromUserId (send message user) and ToUserId (receive message user).
Here are the tables :
Current result -
Expected result:
Table with dummy data -
CREATE TABLE [dbo].[User](
[Id] [int] NULL,
[UserId] [varchar](5) NULL,
[Name] [varchar](5) NULL,
[Email] [varchar](11) NULL
) ON [PRIMARY]
INSERT [dbo].[User] ([Id], [UserId], [Name], [Email]) VALUES (1, N'user1', N'user1', N'user1#a.com')
INSERT [dbo].[User] ([Id], [UserId], [Name], [Email]) VALUES (2, N'user2', N'user2', N'user2#a.com')
INSERT [dbo].[User] ([Id], [UserId], [Name], [Email]) VALUES (3, N'user3', N'user3', N'user3#a.com')
INSERT [dbo].[User] ([Id], [UserId], [Name], [Email]) VALUES (4, N'user4', N'user4', N'user4#a.com')
INSERT [dbo].[User] ([Id], [UserId], [Name], [Email]) VALUES (5, N'user5', N'user5', N'user5#a.com')
CREATE TABLE [dbo].[Conversation](
[Id] [int] NULL,
[conversationId] [varchar](14) NULL,
[messageId] [varchar](4) NULL,
[fromUserId] [varchar](5) NULL,
[toUserId] [varchar](5) NULL
) ON [PRIMARY]
INSERT [dbo].[Conversation] ([Id], [conversationId], [messageId], [fromUserId], [toUserId]) VALUES (1, N'con-user1user2', N'mes1', N'user1', N'user2')
INSERT [dbo].[Conversation] ([Id], [conversationId], [messageId], [fromUserId], [toUserId]) VALUES (2, N'con-user1user2', N'mes2', N'user1', N'user2')
INSERT [dbo].[Conversation] ([Id], [conversationId], [messageId], [fromUserId], [toUserId]) VALUES (3, N'con-user2user1', N'mes3', N'user2', N'user1')
INSERT [dbo].[Conversation] ([Id], [conversationId], [messageId], [fromUserId], [toUserId]) VALUES (4, N'con-user1user3', N'mes4', N'user1', N'user3')
INSERT [dbo].[Conversation] ([Id], [conversationId], [messageId], [fromUserId], [toUserId]) VALUES (5, N'con-user4user1', N'mes5', N'user4', N'user1')
Can someone help how to includes all the records?
Thanks!
You don't need a join in the outer query. This would be more simply written as:
SELECT U.UserId as Id, U.FullName as Name,
(SELECT COUNT(*)
FROM [Conversation] c
WHERE c.FromUserId = 'user1' AND c.ToUserId = U.UserId
) as SentCount,
(SELECT COUNT(*)
FROM [Conversation] c
WHERE c.ToUserId = 'user1' AND c.FromUserId = U.UserId
) as ReceivedCount
FROM [User] U ;
Notes:
Qualify all column references. This is particularly important for correlation clauses.
Give tables aliases that are abbreviations for the table names.
Only use single quotes for string and date constants. Do not use the for column aliases.
Here is a db<>fiddle.
You don't need the conversation table at your base select. Something like this would work, but can be optimised with subqueries:
Select U.UserId as 'Id',
U.name as 'Name',
isnull(fromSummed.sentCount, 0) 'SentCount',
isnull(ToSummed.ReceivedCount, 0) 'ReceivedCount'
FROM [User] U
outer apply (select count(*) as sentCount from [Conversation] cFrom where cFrom.FromUserId = 'user1' and ToUserId = U.UserId ) fromSummed
outer apply (select count(*) as ReceivedCount from [Conversation] cTo where cTo.ToUserId = 'user1' and cTo.FromUserId = U.UserId) ToSummed
where isnull(fromSummed.sentCount, 0)>0 or isnull(ToSummed.ReceivedCount, 0)>0

Generate missing rows using JOIN / CROSS JOIN

I have 3 tables which are used to fill dynamic from value.
The table is represented by schema below.
User can add as many rows as possible, and the rows are shown to end user by template from FormField table.
The data that is saved in FormValues are only for not null values and any values that missing are not saved.
Now the problem is I have to generate report as expected below.
I have tried various combination of join / cross join, but none of them works as expected.
I am able to achieve this in C# via loops, but not able to do the same via SQL Server.
Script attached for DB
USE [SampleDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormTemplate](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_FormTemplate] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormField](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FormId] [int] NOT NULL,
[FieldName] [nvarchar](50) NULL,
[FieldType] [nvarchar](50) NULL,
CONSTRAINT [PK_FormField] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[FormTemplate] Script Date: 3/2/2020 10:10:22 PM ******/
/****** Object: Table [dbo].[FormValue] Script Date: 3/2/2020 10:10:22 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormValue](
[FormId] [int] NOT NULL,
[FieldId] [int] NOT NULL,
[RowIndex] [int] NOT NULL,
[FormValue] [nvarchar](50) NULL,
CONSTRAINT [PK_FormValue] PRIMARY KEY CLUSTERED
(
[FormId] ASC,
[FieldId] ASC,
[RowIndex] ASC
)
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[FormField] ON
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (1, 1, N'FirstName', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (2, 1, N'LastName', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (3, 1, N'Place', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (4, 1, N'age', N'int')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (5, 1, N'dob', N'date')
GO
SET IDENTITY_INSERT [dbo].[FormField] OFF
GO
SET IDENTITY_INSERT [dbo].[FormTemplate] ON
GO
INSERT [dbo].[FormTemplate] ([Id], [Name]) VALUES (1, N'Sample')
GO
SET IDENTITY_INSERT [dbo].[FormTemplate] OFF
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 1, 1, N'fname1')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 2, 1, N'lname1')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 2, 3, N'lname3')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 4, 5, N'20')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 5, 3, N'10/10/2020')
GO
This answers the original version of the question -- and then some. But I don't update answers to conform to evolving questions.
You seem to want cross joins on three "tables". The third needs to generate the rowindex values:
select f.id as formtemplateid, ff.id as formfieldid, v.rowindex,
fv.value
from formtemplate f cross join
formfield ff cross join
(values (1), (2), (3), (4), (5)) v(rowindex) left join
formvalues fv
on fv.formtemplateid = f.id and
fv.formfieldid = ff.id and
fv.rowindex = v.rowindex
order by f.id, ff.id, v.rowindex;
EDIT:
You can generate up to 100 numbers using a recursive CTE by doing:
with n as (
select 1 as n
union all
select n + 1
from n
where n < 10 -- "10" is however many you want
)
select n.n
from n;

Self join to get the first classID for a report

I have the following table :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[myTable]
(
[importID] [INT] IDENTITY(1,1) NOT NULL,
[classID] [INT] NOT NULL,
[priorReportID] [INT] NOT NULL,
[currentReportID] [INT] NOT NULL,
[dateStamp] AS (GETDATE())
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[myTable] ON
GO
INSERT INTO [dbo].[myTable] ([importID], [classID], [priorReportID], [currentReportID])
VALUES (1, 2069, 3825, 3833), (2, 2069, 3826, 3834),
(3, 2069, 3827, 3835), (4, 2069, 3832, 3836),
(5, 2091, 3889, 3890), (6, 2095, 3894, 3895),
(7, 2098, 3895, 3898), (8, 2098, 3896, 3899),
(9, 2098, 3897, 3900), (10, 2097, 2190, 2193),
(11, 2096, 2188, 2190), (12, 2094, 2187, 2188),
(13, 2093, 2180, 2187)
GO
SET IDENTITY_INSERT [dbo].[myTable] OFF
GO
I am trying to get the first ClassID when a particular report was created.
select *
from mytable
select *
from mytable
where currentReportID = 3833
select *
from mytable
where currentReportID = 3825
select *
from mytable
where currentReportID = 2193
select *
from mytable
where currentReportID = 2190
select *
from mytable
where currentReportID = 2188
select *
from mytable
where currentReportID = 2187
select *
from mytable
where currentReportID = 2180
In the example above: reportID = 2193 was actually created in classID = 2093.
Similarly, reportID = 3833 was created in classID = 2069.
Basically, I need to traverse down the records until there is no more currentReportID = priorReportID condition is satisfied.
Thanks in advance.

update transaction table data with new table id

I have 3 tables with following structure and data.
CREATE TABLE [dbo].[Department]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL
)
CREATE TABLE [dbo].[Department_New]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL
)
CREATE TABLE [dbo].[Employee]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[DepId] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL
)
SET IDENTITY_INSERT [dbo].[Department] ON
INSERT [dbo].[Department] ([Id], [Name])
VALUES (1, N'HR'), (2, N'IT'), (3, N'Account'), (4, N'Finance'), (5, N'Software')
SET IDENTITY_INSERT [dbo].[Department] OFF
SET IDENTITY_INSERT [dbo].[Department_New] ON
INSERT [dbo].[Department_New] ([Id], [Name])
VALUES (1, N'IT'), (2, N'HR'), (3, N'Software'), (4, N'Account'),
(5, N'iDontKnow'), (6, N'Finance')
SET IDENTITY_INSERT [dbo].[Department_New] OFF
SET IDENTITY_INSERT [dbo].[Employee] ON
INSERT [dbo].[Employee] ([Id], [DepId], [Name])
VALUES (1, 1, N'abc'), (2, 2, N'zxc'), (3, 1, N'xcv'),
(4, 3, N'cvb'), (5, 4, N'vbn'), (6, 1, N'bnm'),
(7, 3, N'asd'), (8, 3, N'sdf'), (9, 2, N'dfg'),
(10, 4, N'fgh'), (11, 5, N'ghj'), (12, 5, N'hjk'),
(13, 6, N'jkl'), (14, 6, N'qwe'), (15, 2, N'wre'),
(16, 3, N'ert'), (17, 6, N'rty'), (18, 1, N'tyu')
SET IDENTITY_INSERT [dbo].[Employee] OFF
As of now Employee table has old depId. I just want to update with new depId. I can not write for loop because employee table contains more than 1,000,000 rows of data.
What I have tried
CREATE PROCEDURE UpdateDepId
AS
BEGIN
DECLARE #totalRecords INT
DECLARE #I INT
SELECT #I = 1
SELECT #totalRecords = COUNT(DISTINCT DepId) FROM Employee
DECLARE #DPID INT
DECLARE #Id INT
--drop table #Temp
IF OBJECT_ID('tempdb.dbo.#Temp', 'U') IS NOT NULL
DROP TABLE #Temp;
CREATE TABLE #Temp
(
Id INT IDENTITY(1,1),
DepId INT
)
INSERT INTO #Temp
SELECT DISTINCT DepId
FROM Employee
ORDER BY DepId
WHILE (#I <= #totalRecords)
BEGIN
SET #DPID = (SELECT DepId FROM #Temp WHERE Id = #I)
EXEC UpdateDepByDepId #DPID
SELECT #I = #I + 1
END
DROP TABLE #Temp
END
CREATE PROCEDURE UpdateDepByDepId
#DepId INT
AS
BEGIN
DECLARE #DepIdNew INT
SET #DepIdNew = (SELECT Id FROM Department_New
WHERE Name IN (SELECT Name FROM Department WHERE id = #DepId))
SELECT #DepIdNew AS NewDepId, #DepId AS OldDepId
IF ISNULL(#DepIdNew, 0) <> 0
BEGIN
UPDATE Employee
SET DepId = #DepIdNew
WHERE DepId = #DepId
END
END
But it is not working for me. Please help
Use an update and from:
update e
set depid = dn.id
from employee e join
department d
on e.depid = d.id join
department_new dn
on dn.name = d.name;

SQL Server: How to update table based on subquery in where clause?

I have a table (with data) like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[lTab](
[log_id] [int] IDENTITY(1,1) NOT NULL,
[JobName] [nvarchar](40) NULL,
[startTime] [datetime] NULL,
[endTime] [datetime] NULL,
[BatchId] [int] NULL,
[status] [varchar](10) NULL,
[messag] [varchar](255) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[lTab] ON
INSERT [dbo].[lTab] ([log_id], [JobName], [startTime], [endTime], [BatchId], [status], [messag]) VALUES (1, N'Job1', CAST(0x00009EB700FBF56F AS DateTime), NULL, 2, N'START', N'Test')
INSERT [dbo].[lTab] ([log_id], [JobName], [startTime], [endTime], [BatchId], [status], [messag]) VALUES (2, N'Job2', NULL, CAST(0x00009EB700FBF975 AS DateTime), 2, N'START', N'Test')
INSERT [dbo].[lTab] ([log_id], [JobName], [startTime], [endTime], [BatchId], [status], [messag]) VALUES (3, N'Job3', CAST(0x00009EB700FC287F AS DateTime), NULL, 2, N'START', N'Test')
INSERT [dbo].[lTab] ([log_id], [JobName], [startTime], [endTime], [BatchId], [status], [messag]) VALUES (4, N'Job3', NULL, CAST(0x00009EB700FC2CC6 AS DateTime), 2, N'END', N'Test')
SET IDENTITY_INSERT [dbo].[lTab] OFF
I'm trying to update endTime based on Jobname and max(log_id).
DECLARE #Jname VARCHAR(10)
SET #Jname = 'Job3'
UPDATE lTab
SET endTime = GETDATE()
WHERE log_id = (SELECT JobName, MAX(log_id) AS log_id FROM dbo.lTab WHERE jobname = #Jname GROUP BY JobName)
I get an error
sg 116, Level 16, State 1, Line 6
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
How to get this work?
WITH q AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY JobName ORDER BY log_id DESC) AS rn
FROM lTab
WHERE JobName = #Jname
)
UPDATE q
SET endTime = GETDATE()
WHERE rn = 1
Take out the Jobname from the select list in the subquery.
You don't actually need it to get the result you need, SQL Server will still return the right log_id.
What you have won't work since you are returning 2 fields (Jobname,MAX(Log_id)) and trying to match Log_id to it.
This query:
(SELECT JobName, MAX(log_id) AS log_id FROM dbo.lTab WHERE jobname = #Jname GROUP BY JobName)
is returning multiple results, exclude JobName from your query.
Yet a better option would be
UPDATE tablename SET tablename.field1 = sourceTable.dataField
From tablename
join sourceTable On tablename.keyfield = sourceTable.keyField
Where sourceTable.jobname = #jobName