Change row values from single column into different column names - sql

I have a table, EmpDetail, with three columns:
EMP_NAME DETAIL_ID DETAIL
----------------------------------
ABC ADDRESS abc123
ABC PHONE 12345
ABC EMAIL abc#xyz
BCD ADDRESS bcd234
BCD PHONE 23456
BCD EMAIL bcd#345
I want to create a new table such that the values from the DETAIL_ID become the new column names:
EMP_NAME ADDRESS PHONE EMAIL
----------------------------------------
ABC abc123 12345 abc#xyz
BCD bcd234 23456 bcd#345
I have already tried Join but i am unable to get the desired result.
Please suggest a way to do this.

Here's an example of how to join for just two details, address and phone:
insert into NewTable
(EMP_NAME, ADDRESS, PHONE)
select name.EMP_NAME
, addr.DETAIL
, phone.DETAIL
from (
select distinct EMP_NAME
from OldTable
) name
left join
OldTable addr
on addr.EMP_NAME = name.EMP_NAME
and addr.DETAIL_ID = 'ADDRESS'
left join
OldTable phone
on phone.EMP_NAME = name.EMP_NAME
and phone.DETAIL_ID = 'PHONE'
Grouping also works, probably a little simpler:
insert into NewTable
(EMP_NAME, ADDRESS, PHONE)
select EMP_NAME
, max(case when DETAIL_ID = 'ADDRESS' then DETAIL end)
, max(case when DETAIL_ID = 'PHONE' then DETAIL end)
from OldTable
group by
EMP_NAME

CREATE TABLE NewTable AS
SELECT EMP_NAME ,
wm_concat(ADDRESS) ADDRESS,
wm_concat(PHONE) PHONE,
wm_concat(EMAIL) EMAIL
FROM
(SELECT EMP_NAME ,
CASE
WHEN DETAIL_ID='ADDRESS'
THEN DETAIL
ELSE NULL
END ADDRESS ,
CASE
WHEN DETAIL_ID='PHONE'
THEN DETAIL
ELSE NULL
END PHONE ,
CASE
WHEN DETAIL_ID='EMAIL'
THEN DETAIL
ELSE NULL
END EMAIL
FROM EmpDetail
)
GROUP BY EMP_NAME;

Related

How can I insert new data from one table to another table without inserting any duplicate data?

I am trying to append new address data from [clients_tbl] to [Address_tbl]. Following is the structure of the Client's table
AutoNo CNR FNC SNC AM1 AM2 AM3 AM4 AM5 AF1 AF2 AF3 AF4 AF5
3 1 FirstName Surname A1 A2 A3 A4 Zipcode D A B A Zipcode
4 2 FirstName1 Surname1 C D E F Zipcode X Y Z A Zipcode
AM = Address Mother(AM1 = Address1 of mother, AM2 = Address2 of mother, AM3 = Town of mother, AM4 = City of mother, AM5 = Zipcode of mother)
AF = Address Father(Same structure as above for father)
Following is the structure of the Address table:
AddrsID CNR RelationID AddressTypeID Address1 Address2 Address3 Address4 Address5
1 1 4610 1 A1 A2 A3 A4 Zipcode
123 1 8653 1 D A B A4 Zipcode
Now the relation ID in the Address table comes from the Relation Table:
RelationID CNR RelationTypeID FirstName Surname
1 1 1 First Name Surname
4610 1 2 FirstNameParent 1 SurnameParent1
8653 1 3 FirstNameParent 2 SurnameParent2
11840 1 4 FirstNameGuarian SurnameGuarian
Now imagine that the new data is inserted into the client's table with CNR = 2. I want to insert the Address data into the Address table from the client's table. I wanted to know how can I achieve this. I have tried a few codes but it's not working. Please look at the code below to insert new mother's address data and father's data from client's table to address table:
INSERT INTO [dbo].[1-03_RelationsAddress_tbl]
([CNR]
,[AddressTypeID]
,[Address1]
,[Address2]
,[Address3]
,[Address4]
,[Address5]
,[LastUpdated]
,[UpdatedBy]
,[Active])
Select [CNR]
,1
,[AM1]
,[AM2]
,[AM3]
,[AM4]
,[AM5]
,getdate()
,124
,1
from dbo.[1-01_Clients_tbl]
Where ([AM1] is not null or [AM2] is not null or [AM3] is not null or [AM4] is not null or [AM5] is not null)
AND (dbo.[1-01_Clients_tbl].CNR NOT IN (Select [dbo].[1-03_RelationsAddress_tbl].CNR from [1-03_RelationsAddress_tbl]))
INSERT INTO [dbo].[1-03_RelationsAddress_tbl]
([CNR]
,[AddressTypeID]
,[Address1]
,[Address2]
,[Address3]
,[Address4]
,[Address5]
,[LastUpdated]
,[UpdatedBy]
,[Active])
Select [CNR]
,1
,[AF1]
,[AF2]
,[AF3]
,[AF4]
,[AF5]
,getdate()
,124
,1
from dbo.[1-01_Clients_tbl]
Where ([AF1] is not null or [AF2] is not null or [AF3] is not null or [AF4] is not null or [AF5] is not null)
AND (dbo.[1-01_Clients_tbl].CNR NOT IN (Select [dbo].[1-03_RelationsAddress_tbl].CNR from [1-03_RelationsAddress_tbl]))
But the issue is now when Mother's data is inserted into the Address table, the Father's data is not inserted as the Address table already contains the CNR value. How can I insert only the new data without having to insert duplicates? Also, is it advisable to truncate the Address table whenever we are going to update data from client's table to address table so that we don't have to use any conditions?
Thanks a million in advance.

Not able to add row wise data in column form

EmpID (Primary Key) Sale Items Paid
ABC chair Yes
WXY chair Under Review
PER Laptop Yes
ABC Chair Yes
Now i want to create another table where i want to insert data Like below
Emp ID Chair Laptop
ABC 2 0
WXY 1 0
My query to insert is
Select Emp Id from EMP,count(sales_item) as chair where Sales_Item = 'chair'
it is working now how to add Laptop (3rd Column ) . can you please suggest
You would use conditional aggregation:
Select EmpId,
sum(case when sales_item = 'chair' then 1 else 0 end) as chairs,
sum(case when sales_item = 'laptop' then 1 else 0 end) as laptops
from EMP
group by EmpId;
There is no reason to store this in a separate table. If you like, you can create a view. Then when you access the view, you know the data is up-to-date.
You could use pivot for the expected result:
DECLARE #t TABLE(
EmpID varchar(3)
,SaleItems varchar(10)
,Paid varchar(20)
)
INSERT INTO #t VALUES
('ABC', 'chair', 'Yes')
,('WXY', 'chair', 'Under Review')
,('PER', 'Laptop', 'Yes')
,('ABC', 'Chair', 'Yes')
SELECT piv.EmpID, ISNULL(piv.chair, 0) AS chair, ISNULL(piv.Laptop, 0) AS Laptop
FROM(
SELECT EmpID, SaleItems, 1 cnt
FROM #t
) x
PIVOT
(
SUM(cnt)
FOR SaleItems IN ([chair], [Laptop])
) piv

Oracle SQL - break 1 row into 2 rows

I have the following table:
create table members
(
member_number number(10),
title varchar2(5),
lastname varchar2(30),
personal_email varchar2(20),
work_email varchar2(20)
)
with the data
Insert into MEMBERS
(MEMBER_NUMBER, TITLE, LASTNAME, PERSONAL_EMAIL, WORK_EMAIL)
Values
(11, 'MR', 'Dore', 'personal#email.com', 'work#email.com');
COMMIT;
select member_number, title, lastname,
decode (:pi_email,
'Work', work_email, personal_email) destination
from members
where member_number = 11
and decode (:pi_email,
'Work', work_email, personal_email) is not null
union
select member_number, title, lastname, work_email
from members
where member_number = 11
and :pi_email = 'Both'
and work_email is not null
Question:
Is it possible to re-write the code using 1 select and not using a UNION.
I want to be able to pass pi_email value of 'Work' and select the work_email, alternatively select the personal_email, however if I pass 'Both' I want to select both email addresses in 2 lines/rows.
If I understand correctly, you can unpivot the data and then use a where clause. In Oracle 12C+, you can do this using a lateral join:
select m.member_number, m.title, m.lastname, e.email
from members m cross join lateral
(select 'work' as which, m.work_email as email from dual union all
select 'personal' as which, m.personal_email from dual
) e
where :pi_email in (e.which, 'both');
In earlier versions of Oracle, you can do something similar with union all in the from clause.
How about a CTE with additional column (what in my example, which tells what kind of an e-mail address is that)?
Sample data:
SQL> select * from members;
MEMBER_NUMBER TITLE LASTNAME PERSONAL_EMAIL WORK_EMAIL
------------- ----- ---------- -------------------- --------------------
11 MR Dore personal#email.com work#email.com
Query (runs in SQL*Plus) - fetch work e-mail address:
SQL> set ver off
SQL> with data as
2 (select 'P' what, member_number, title, lastname, personal_email email
3 from members
4 union all
5 select 'W' what, member_number, title, lastname, work_email email
6 from members
7 )
8 select member_number,
9 title,
10 lastname,
11 email
12 from data
13 where member_number = &pi_memnum
14 and (what = '&&pi_email' or '&&pi_email' is null);
Enter value for pi_memnum: 11
Enter value for pi_email: W
MEMBER_NUMBER TITLE LASTNAME EMAIL
------------- ----- ---------- --------------------
11 MR Dore work#email.com
Another example, which fetches both e-mail addresses (what is left NULL):
SQL> undefine pi_email
SQL>
SQL> /
Enter value for pi_memnum: 11
Enter value for pi_email:
MEMBER_NUMBER TITLE LASTNAME EMAIL
------------- ----- ---------- --------------------
11 MR Dore personal#email.com
11 MR Dore work#email.com
SQL>
If you don't use SQL*Plus, the last two lines (i.e. the where clause) would be
where member_number = :pi_memnum
and (what = :pi_email or :pi_email is null);

How can I use SQL Pivot Table to turn my rows of data into columns

In SQL 2008, I need to flatten a table and show extra rows as columns. All I can find are queries with calculations. I just want to show the raw data. The data is like as below (simplified):
ID# Name Name_Type
1 Mary Jane Legal
1 MJ Nickname
1 Smith Maiden
2 John Legal
3 Suzanne Legal
3 Susie Nickname
I want the data to show as:
ID# Legal Nickname Maiden
1 Mary Jane MJ Smith
2 John
3 Suzanne Susie
where nothing shows in the column if there is not a row existing for that column. I'm thinking the Pivot Table method should work.
PIVOT requires you to use an aggregate. See this post for a better explanation of how it works.
CREATE TABLE #MyTable
(
ID# INT
, Name VARCHAR(50)
, Name_Type VARCHAR(50)
);
INSERT INTO #MyTable VALUES
(1, 'Mary Jane', 'Legal')
, (1, 'MJ', 'Nickname')
, (1, 'Smith', 'Maiden')
, (2, 'John', 'Legal')
, (3, 'Suzanne', 'Legal')
, (3, 'Susie', 'Nickname');
SELECT *
FROM
(
SELECT * FROM #MyTable
) AS Names
PIVOT (MAX(NAME)
FOR Name_Type IN ([Legal], [Nickname], [Maiden]))
AS PVT;
DROP TABLE #MyTable;
Try this (replace "new_Table" with your table - name and "ID_" with your id - column):
SELECT ID_ AS rootID, (
SELECT Name
FROM new_table
WHERE Name_type = 'legal'
AND new_table.ID_ = rootID
) AS legal,
(
SELECT Name
FROM new_table
WHERE Name_type = 'Nickname'
AND ID_ = rootID
) AS Nickname,
(
SELECT Name
FROM new_table
WHERE Name_type = 'Maiden'
AND ID_ = rootID
) AS Maiden
FROM new_table
GROUP BY rootID;

SQL Server : query to update record with latest entry

I have a table that maintains records of employers and employees' data. Something like this
EmployerName EmployerPhone EmployerAddress EmployeeName EmployeePhone EmployeeAddress Date
-------------------------------------------------------------------------------------------------------
John 12345 NewYork Harry 59786 NewYork 12-1-1991
Mac 22345 Bankok John 12345 Delhi 12-3-1991
Smith 54732 Arab Amar 59226 China 21-6-1991
Sarah 12345 Bhutan Mac 22345 NewYork 5-9-1991
Root 85674 NewYork Smith 54732 Japan 2-11-1991
I have another table that will have generic records on the basis of phone number (both employers and employees).
Table structure is as following
Phone Name Address
I want to put latest records according to date from Table1 to Table2 on the basis of phone..
Like this
Phone Name Address
-----------------------
59786 Harry NewYork
22345 Mac NewYork
59226 Amar China
12345 Sarah Bhutan
22345 Mac NewYork
85674 Root NewYork
54732 Smith Arab
I've written many queries but couldn't find anyone resulted as required.
Any kind of help will be appreciated.
For initialize the table without phone duplicates:
INSERT IGNORE INTO Table2 (Phone, Name, Address)
SELECT X.* FROM (
SELECT EmployeeName,EmployeePhone,EmployeeAddress FROM Table1
UNION
SELECT EmployerName,EmployerPhone,EmployerAddress FROM Table1
) X
WHERE NOT EXISTS (SELECT Phone FROM Table2 WHERE Phone=X.Phone)
I think this is what you are looking for if I understand your question correctly. Should work for a once-off
DECLARE #restbl TABLE
(
Name varchar(100),
Phone varchar(20),
Addr varchar(100),
[Date] date,
RecType varchar(100)
)
INSERT INTO #restbl
SELECT EmployerName, EmployerPhone, NULL, MAX([Date]), 'Employer'
FROM #tbl
GROUP BY EmployerName, EmployerPhone
INSERT INTO #restbl
SELECT EmployeeName, EmployeePhone, NULL, MAX([Date]), 'Employee'
FROM #tbl
GROUP BY EmployeeName, EmployeePhone;
WITH LatestData (Name, Phone, [Date])
AS
(
SELECT Name, Phone, MAX([Date])
FROM #restbl
GROUP BY Name, Phone
)
INSERT INTO FinalTable (Name, Phone, [Address])
SELECT DISTINCT ld.Name, ld.Phone, ISNULL(tEmployer.EmployerAddress, tEmployee.EmployeeAddress) AS [Address]
FROM LatestData ld
LEFT JOIN #tbl tEmployer ON ld.Name = tEmployer.EmployerName AND ld.Phone = tEmployer.EmployerPhone AND ld.Date = tEmployer.Date
LEFT JOIN #tbl tEmployee ON ld.Name = tEmployee.EmployeeName AND ld.Phone = tEmployee.EmployeePhone AND ld.Date = tEmployee.Date