SQL left join for inactive records - sql

I have 2 tables. One of them has actual names and the other one has nicknames used by those people.
CREATE TABLE [dbo].[Customer](
[id] [int] IDENTITY(1,1) NOT NULL,
[firstName] [varchar](50) NULL,
[lastName] [varchar](50) NULL,
[active] [bit] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[CustomerAKA](
[id] [int] NULL,
[akaFirstName] [varchar](50) NULL,
[akaLastName] [varchar](50) NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Customer] ON
INSERT [dbo].[Customer] ([id], [firstName], [lastName], [active]) VALUES (1, N'Op', N'Test', 0)
INSERT [dbo].[Customer] ([id], [firstName], [lastName], [active]) VALUES (2, N'M', N'J', 1)
INSERT [dbo].[Customer] ([id], [firstName], [lastName], [active]) VALUES (3, N'John', N'Doe', 1)
SET IDENTITY_INSERT [dbo].[Customer] OFF
INSERT [dbo].[CustomerAKA] ([id], [akaFirstName], [akaLastName]) VALUES (1, N'Hello', N'Test')
INSERT [dbo].[CustomerAKA] ([id], [akaFirstName], [akaLastName]) VALUES (1, N'Mahalo', N'Test')
INSERT [dbo].[CustomerAKA] ([id], [akaFirstName], [akaLastName]) VALUES (3, N'Jonny', N'Doe')
My query is :
select *
from dbo.Customer c1
left join dbo.CustomerAKA c2 on c2.id = c1.id
where not exists ( select *
from dbo.Customer c
where c.id = c1.id
and c.active = 0 )
Even though Op Test is not active, I still want to get the nicknames for him:
1 Hello Test
1 Mahalo Test
So my output should be :
M J
John Doe
Jonny Doe
Hello Test
Mahalo Test
Any ideas?

I think you want union all:
select c.firstname, c.lastname
from customer c
union all
select ca.akafirstname, c.akalastname
from customeraka ca join
customer c
on ca.id = c.id
where c.active = 1;

Try this:
/*
WITH
Customer (id, firstName, lastName, active) AS
(
VALUES
(1, 'Op', 'Test', 0)
, (2, 'M', 'J', 1)
, (3, 'John', 'Doe', 1)
)
, CustomerAKA (id, akaFirstName, akaLastName) AS
(
VALUES
(1, 'Hello', 'Test')
, (1, 'Mahalo', 'Test')
, (3, 'Jonny', 'Doe')
)
*/
SELECT firstName, lastName
FROM Customer
WHERE active = 1
UNION ALL
SELECT c2.akaFirstName AS firstName, c2.akaLastName AS lastName
FROM CustomerAKA c2
JOIN Customer c1 ON c1.id=c2.id;

Not sure about what you want
But seems something like
select *
from dbo.Customer c1
left join dbo.CustomerAKA c2 on c2.id = c1.id
where c1.active = 1 or (c1.firstname = "Op" and c1.lastname = "Test")
Order by c1.active desc
Or like
select
coalesce(c2.firstname, c1.firstname) as firstname,
coalesce(c2.lastname, c1.lastname) as lastname
from dbo.Customer c1
Left outer join dbo.CustomerAKA c2 on c2.id = c1.id
Order by c1.active desc

Related

Trying to use CTE to replace codes with names

Expecting to get names instead of codes which is highlighted in yellow.
Employee Table
CREATE TABLE [dbo].[_Employees](
[Name] [nvarchar](50) NULL,
[Code] [nvarchar](50) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[_Employees] ([Name], [Code]) VALUES (N'A', N'1')
GO
INSERT [dbo].[_Employees] ([Name], [Code]) VALUES (N'B', N'2')
GO
INSERT [dbo].[_Employees] ([Name], [Code]) VALUES (N'C', N'3')
GO
Data Table
CREATE TABLE [dbo].[_Details](
[Department] [nvarchar](50) NULL,
[Zone] [nvarchar](50) NULL,
[Place] [nvarchar](50) NULL,
[City] [nvarchar](50) NULL,
[L1] [nchar](10) NULL,
[L2] [nchar](10) NULL,
[L3] [nchar](10) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[_Details] ([Department], [Zone], [Place], [City], [L1], [L2], [L3]) VALUES (N'Department1', N'Zone1', N'Place1', N'City1', N'1 ', N'2 ', N'3 ')
GO
INSERT [dbo].[_Details] ([Department], [Zone], [Place], [City], [L1], [L2], [L3]) VALUES (N'Department2', N'Zone2', N'Place2', N'City2', N'3 ', N'2 ', N'1 ')
GO
INSERT [dbo].[_Details] ([Department], [Zone], [Place], [City], [L1], [L2], [L3]) VALUES (N'Department3', N'Zone3', N'Place3', N'City3', N'2 ', N'3 ', N'1 ')
GO
My Attempt
WITH _Details AS
(
SELECT L1 FROM _Details
UNION ALL
SELECT e.Name FROM _Employees e INNER JOIN _Details d ON e.Code = d.L1
)
SELECT * FROM _Details
Not sure what I am doing wrong?
Simply JOIN the tables:
SELECT
d.[Department], d.[Zone], d.[Place], d.[City],
e1.[Name] AS L1, e2.[Name] AS L2, e3.[Name] AS L3
FROM _Details d
LEFT JOIN _Employees e1 ON d.L1 = e1.Code
LEFT JOIN _Employees e2 ON d.L2 = e2.Code
LEFT JOIN _Employees e3 ON d.L3 = e3.Code
You only need joins. Join the employee table thrice, once per employee column. As L1, L2, and L3 are nullable, you need outer joins.
select
d.[Department], d.[Zone], d.[Place], d.[City],
e1.[Name] as name1,
e2.[Name] as name2,
e3.[Name] as name3
from [dbo].[_Details] d
left join [dbo].[_Employees] e1 on e1.[Code] = d.[L1]
left join [dbo].[_Employees] e2 on e2.[Code] = d.[L3]
left join [dbo].[_Employees] e3 on e3.[Code] = d.[L2];

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

SQL Server output in desired formatted way

I have two tables, tblName and tblCode.
tblName:
CREATE TABLE [dbo].[TblName]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
CONSTRAINT [PK_TblName]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
tblCode:
CREATE TABLE [dbo].[tblCode]
(
[NameId] [int] NULL,
[Code] [varchar](50) NULL,
[Value] [varchar](50) NULL
) ON [PRIMARY]
Code:
INSERT INTO [dbo].[TblName]
([Name])
VALUES
('Rahul'),
('Rohit'),
('John'),
('David'),
('Stephen')
GO
INSERT INTO [dbo].[tblCode] ([NameId], [Code], [Value])
VALUES (1, 'DEL', 'Delivery'),
(1, 'DEL', 'Deployment'),
(2, 'REL', 'Release Management'),
(3, 'REL', 'Release Management'),
(4, 'TEST', 'Testing'),
(4, 'TEST', 'Final Testing')
I am trying to write a query to get all Names which are in tblCode with the Code and Value. For example I have NameId 1 present in tblCode with Code 'DEL' and Value as 'Delivery' and 'Deployment'. Similarly I have NameId 2,3 and 4 in tblCode with same or different Code and Value. So I am trying to get output in such a way if same name with same code is present in tblCode then it should come row with Name and Comma separated values as shown in below desired output.
This is they query I am using but its not giving the output I am looking for.
SELECT
N.Name,
CASE
WHEN C.Code = 'DEL'
THEN C.Value
ELSE ''
END As 'CodeValue'
FROM
TblName N
INNER JOIN
tblCode C ON N.Id = C.NameId
WHERE
C.NameId = 1 AND C.Code IN ('DEL', 'REL', 'TEST')
http://sqlfiddle.com/#!6/bdca78/11/0
CREATE TABLE tblName (id INTEGER, name VARCHAR(255));
INSERT INTO tblName VALUES(1, 'Rahul');
INSERT INTO tblName VALUES(2, 'Rohit');
INSERT INTO tblName VALUES(3, 'John');
INSERT INTO tblName VALUES(4, 'David');
INSERT INTO tblName VALUES(5, 'Steven');
CREATE TABLE tblCode(nameId INTEGER, code VARCHAR(255), value VARCHAR(255));
INSERT INTO tblCode VALUES(1, 'DEL', 'Delivery');
INSERT INTO tblCode VALUES(1, 'DEL', 'Development');
INSERT INTO tblCode VALUES(2, 'REL', 'Release Management');
INSERT INTO tblCode VALUES(3, 'REL', 'Release Management');
INSERT INTO tblCode VALUES(4, 'TEST', 'Testing');
INSERT INTO tblCode VALUES(4, 'TEST', 'Final Testing');
SELECT name,
codeValue
FROM
(SELECT tblName.name AS name,
STUFF((SELECT ',' + tblCode.value
FROM tblCode
WHERE tblCode.nameId = tblName.id
FOR XML PATH('')), 1 ,1, '') AS codeValue
FROM tblName) inline_view
WHERE codeValue IS NOT NULL;
Edit
ZoharPeled's solution is correct. This solution returns the name and a comma separated list of value and does not consider the code.
Zohar aggregates the list of value per code, which I think is what's required. OP, if the objective is to aggregate per name per code, including code in the output would make the result set more meaningful.
The following links show the difference, first is my SQL statement, then Zohar's.
My SQL: http://sqlfiddle.com/#!6/94fd0/1/0
Zohar's SQL: http://sqlfiddle.com/#!6/94fd0/2/0
Here is one way to do it:
;WITH CTE AS
(
SELECT DISTINCT
[NameId]
,[Code]
,(
SELECT STUFF(
(SELECT ',' + Value
FROM dbo.tblCode t1
WHERE t0.Code = t1.Code
AND t0.NameId = t1.NameId
FOR XML PATH(''))
, 1, 1, '')
) AS CodeValue
FROM dbo.tblCode t0
)
SELECT Name, CodeValue
FROM tblName
INNER JOIN CTE ON Id = CTE.NameId
ORDER BY Id
Results:
Name CodeValue
Rahul Delivery,Deployment
Rohit Release Management
John Release Management
David Testing,Final Testing
Read this SO post for an explanation on how to use STUFF and FOR XML to create a concatenated string from multiple rows.
You can see a live demo on rextester.

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

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

sql server query: how to select customers with more than 1 order

I am a sql server newbie and trying to select all the customers which have more than 1 orderid. The table looks as follows:
CREATE TABLE [dbo].[orders](
[customerid] [int] NULL,
[orderid] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[orders] ([customerid], [orderid]) VALUES (1, 2)
INSERT [dbo].[orders] ([customerid], [orderid]) VALUES (1, 3)
INSERT [dbo].[orders] ([customerid], [orderid]) VALUES (2, 4)
INSERT [dbo].[orders] ([customerid], [orderid]) VALUES (2, 5)
INSERT [dbo].[orders] ([customerid], [orderid]) VALUES (3, 1)
select customerid
, count(*) as order_count
from orders
group by
customerid
having count(*) > 1
as you'll probably need customer data at some point, you could also try:
select *
from customers
where exists (
select count(*)
from orders
where customers.id = customerid
group by customerid
having count(*) > 1
)