SQL View Assign Alternating Data from Another Table - sql

I cannot explain this thoroughly with words as English is not my native language so I will try visual presentation. First, I have a table that looks like this let's call it tblPerson:
tblPerson
ID Name
1 John
2 Paul
3 James
Then I have another table tblPhones:
tblPhones
ID Mobile
1 123456
2 654321
Now for my question, is it possible to create a view that will look like this:
Person-Phone
Name Mobile
John 123456
Paul 654321
James 123456
What I want to display is a list of person, and use the tblPhones to assign the mobile column but assign it alternately. So if a new person is added lets say Mark. The view would look like this:
Person-Phone
Name Mobile
John 123456
Paul 654321
James 123456
Mark 654321
How can I query this?

Try this:
SELECT Name, Mobile
FROM (
SELECT Name,
ROW_NUMBER() OVER (ORDER BY ID) As rn
FROM tblPerson) AS t1
INNER JOIN (
SELECT Mobile,
ROW_NUMBER() OVER (ORDER BY ID) AS rn,
COUNT(*) OVER () AS cnt
FROM tblPhones
) AS t2 ON (t1.rn - 1) % cnt + 1 = t2.rn
Demo here

#Giorgos beat me to it, but here's my version. You don't need the row_number window function assuming the IDs are contiguous (if they're not, you do :).
CREATE TABLE #tblPerson (ID INT,Name VARCHAR(5));
CREATE TABLE #tblPhones (ID INT, Mobile VARCHAR(6));
INSERT INTO #tblPerson(ID, Name) VALUES( 1, 'John'),( 2, 'Paul'),( 3, 'James');
INSERT INTO #tblPhones(ID, Mobile) VALUES( 1,'123456'),( 2,'654321');
SELECT
Name, Mobile
FROM #tblPerson
JOIN #tblPhones ON #tblPhones.ID = ((#tblPerson.ID-1) % (SELECT COUNT(*) FROM #tblPhones) +1)
ORDER BY #tblPerson.ID

Related

Merging Duplicate Rows with SQL

I have a table that contains usernames, these names are duplicated in various forms, for example, Mr. John is replicated as John Mr. I want to combine the two rows using their unique phone numbers in SQL.
I want a new table in this form after removing the duplicates
you can do it with ROW_NUMBER window function.
First, you need to group the data by your unique column (Phone_Number), then sort by name.
Preparing the table and example data:
DECLARE #vCustomers TABLE (
Name NVARCHAR(25),
Phone_Number NVARCHAR(9),
Address NVARCHAR(25)
)
INSERT INTO #vCustomers
VALUES
('Mr John', '234881675', 'Lagos'),
('Mr Felix', '234867467', 'Atlanta'),
('Mrs Ayo', '234786959', 'Doha'),
('John Mr', '234881675', 'Lagos'),
('Mr Jude', '235689760', 'Rabat'),
('Ayo', '234786959', 'Doha'),
('Jude', '235689760', 'Rabat')
After that, removing the duplicate rows:
DELETE
vc
FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY Phone_Number ORDER BY Name DESC) AS RN
FROM #vCustomers
) AS vc
WHERE RN > 1
SELECT * FROM #vCustomers
As final, the result:
Name
Phone_Number
Address
Mr John
234881675
Lagos
Mr Felix
234867467
Atlanta
Mrs Ayo
234786959
Doha
Mr Jude
235689760
Rabat

Combine multiple value into 1 for Impala SQL

I want to combine multiple product entries into 1 and also sum their price. Currently, the database looks like this :
Name Product Price
Zack Vanilla Twist 1
Jane Lolipop 0.5
Zack Lolipop 0.5
Zack Candymint 0.5
Jane ChocoLoco LM 1.5
I want to change the look of this into something like this:
Name Product sum(Price)
Zack Vanilla Twist, Lolipop, Candymint 2
Jane Lolipop, ChocoLoco LM 2
How to do this using Impala SQL?
This query works for MySQL, this might help you.
select Name, group_concat(`product` separator ', ') Product, sum(Price)
from tempt
group by Name
order by Name desc
dbfiddle here
declare #temp table (Name varchar(50), product varchar(50), Price decimal(3,1))
insert into #temp values ('Zack','Vanilla Twist',1)
insert into #temp values ('Jane','Lolipop',0.5)
insert into #temp values ('Zack','Lolipop',0.5)
insert into #temp values ('Zack','Candymint',0.5)
insert into #temp values ('Jane','ChocoLoco LM',1.5)
-- No cursor, Whil loop, or User defined function:
SELECT
Name,
STUFF((
SELECT ', ' + product
FROM #temp
WHERE (name = Results.name)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS Product
,sum(Price) as [Sum(Price)]
FROM #temp Results
GROUP BY name
Output:
Name Product Sum(Price)
Jane Lolipop, ChocoLoco LM 2
Zack Vanilla Twist, Lolipop, Candymint 2

SQL Auto-populate ID column based on another column

I have a workflow where source table is used to populate the destination table.
I have tried to simulate this workflow in the code below.
-- creating/populating source table
CREATE TABLE #SourceTable
(
CampaignName VARCHAR(50),
CustomerNumber INT
)
INSERT INTO #SourceTable
VALUES ('Campaign1', 1111), ('Campaign1', 2222), ('Campaign1', 3333),
('Campaign2', 4444), ('Campaign2', 2222), ('Campaign2', 1111)
-- create/populate destination table
CREATE TABLE #DestinationTable
(
CampaignID INT,
CampaignName VARCHAR(50),
CustomerNumber INT
)
-- Simulating populating the #DestinationTable
INSERT INTO #DestinationTable (CampaignName, CustomerNumber)
SELECT CampaignName, CustomerNumber
FROM #SourceTable
The source table will get created in some way, but then it is used to populate the destination table in the same way as my sample code.
The destination table is at CustomerNumber level. I want to autopopulate an ID field (without the user having to code it in) that will give a new number at CampaignName level.
So for example, I want the output of the #DestinationTable to be:
CampaignID CampaignName CustomerNumber
------------------------------------------
1 Campaign1 1111
1 Campaign1 2222
1 Campaign1 3333
2 Campaign2 4444
2 Campaign2 2222
2 Campaign2 1111
But I need the CampaignID column to be auto-populated whenever new rows are being inserted, like an IDENTITY column, but instead of giving each row a number, I need it to give each CampaignName a new number.
Is that possible?
Thanks
This one can be achieved using dense_rank().
SELECT dense_rank() over (order by CampaignName) as rn, CampaignName, CustomerNumber
FROM #SourceTable
To validate if your customer number and campaign name already existed on your destination use not exists keyword.
SELECT dense_rank() over (order by t1.CampaignName) as rn, t1.CampaignName, t1.CustomerNumber
FROM #SourceTable t1
WHERE not exists (select 1 from #DestinationTable t2
where t2.CustomerNumber = t1.CustomerNumber and t2.CampaignName = t1.CampaignName)

How to combine columns from 2 tables into 1 without using JOIN

I am using SQL Server 2008. I have 2 table variables like
FirstName
==========
Little
John
Baby
LastName
==========
Timmy
Doe
Jessica
And I want the result table be:
First Last
=====================
Little Timmy
John Doe
Baby Jessica
Note that there is no PK can join the 2 tables. I am trying to use a cursor but not sure how to start.
---- Updated -----
I know it's a rare case, but I am writing a script to clean up legacy data. The only way we know "Little" goes with "Timmy" is that they are both the first record of the table. Would it help if we had PK for the tables but there is no relation?
ID FirstName
==========
1 Little
2 John
3 Baby
----------
ID LastName
==========
4 Timmy
5 Doe
6 Jessica
----------
I am not familiar with TSQL so I thought I can loop through the 2 tables like looping through Arrays in memory.
You could try something like this, to match up based on row numbers:
SELECT FirstName AS First, LastName AS Last
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, FirstName
FROM FirstName
) t1
INNER JOIN
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, LastName
FROM LastName
) t2
ON t1.RowNum = t2.RowNum
But don't take this as a signal that you don't need keys.
You can't reliably join these two table variables without identities. Assuming they are being populated in an ordinal manner in the first place, each table could be created with identities as follows:
DECLARE #first TABLE(ID INT IDENTITY(1,1), NameFirst VARCHAR(30));
DECLARE #last TABLE(ID INT IDENTITY(1,1), NameLast VARCHAR(30));
-- Note that we don't need to list column names here
INSERT INTO #first VALUES('Little');
INSERT INTO #first VALUES('John');
INSERT INTO #first VALUES('Baby');
INSERT INTO #last VALUES('Timmy');
INSERT INTO #last VALUES('Doe');
INSERT INTO #last VALUES('Jessica');
SELECT n1.NameFirst
, n2.NameLast
FROM #first n1
INNER JOIN #last n2 ON n1.ID=n2.ID;
Result:
NameFirst NameLast
------------------------------ ------------------------------
Little Timmy
John Doe
Baby Jessica
There is no such thing as a "first record". Reading order is totally undefined. This holds true in practice as well! You will see random row order in practice.
You need to define a sorting order. After doing that you can query like this:
SELECT FirstName AS First, LastName AS Last
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS r, FirstName
FROM FirstName
) t1
INNER JOIN
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS r, LastName
FROM LastName
) t2
ON t1.r = t2.r
Notice the placeholder "SORT ORDER HERE". Need to fill that in. Example: "ID" or "FirstName".
Edit: Having seen your edit I added sort order on ID. This will work now.
Here is a hack, that might work in your case:
select t1.id, t1.name, t2.name
from (select name, row_number() over (partition by null order by (select NULL)) as id
from t1
) t1 join
(select name, row_number() over (partition by null order by (select NULL)) as id
from t2
) t2
on t1.id = t2.id
In my experience, the row_number() with the subquery for the order by means that no sort is actually done, but the rows are brought in sequentially. This is more likely to work if you are using a single threaded instance.
And, I don't guarantee that it will work! Definitely check the results! If this doesn't work, you might be able to get the same effect by using temporary tables.
Is this data coming from outside the database world? If you have to perform this process more than once, then you should handle the problem either externally or on input into the database.
Building on solution #JohnDewey presented, you can sort the records into the table variables. In practice, it will create a relation between the values based on the order of the records:
DECLARE #first TABLE(sequence INT IDENTITY(1,1), FirstName VARCHAR(30));
DECLARE #last TABLE(sequence INT IDENTITY(1,1), LastName VARCHAR(30));
INSERT INTO #first(FirstName)
SELECT FirstName FROM TableFisrt ORDER BY id;
-- sequence FirstName
-- ======== =========
-- 1 Little
-- 2 John
-- 3 Baby
INSERT INTO #last(LastName)
SELECT FirstName FROM TableLast ORDER BY id;
-- sequence LastName
-- ======== =========
-- 1 Timmy
-- 2 Doe
-- 3 Jessica
SELECT frs.FirstName, lst.LastName
FROM #first frs
INNER JOIN #last lst ON frs.sequence = lst.sequence;
-- sequence FirstName
-- ======== =========
-- Little Timmy
-- John Doe
-- Baby Jessica

SQL Query to update a column based on the values of other columns in the same table

Ok this is difficult to phrase, so here goes...
I am using MS SQL Server 2008 R2. I have a temp table that lets say has two already populated columns. There is a third empty column I want to populate based on the value of the first two columns. What I want to do is create a guid (using NEWUID()) for each matching combo of col1 and col2. Here is a visual example:
Lets say I have a temp table that looks like this initially:
Name Activity SpecialId
James Running
James Running
James Walking
John Running
John Running
John Walking
I want it to get updated with new GUIDs so that it looks like this:
Name Activity SpecialId
James Running SOMEFAKEGUID_1
James Running SOMEFAKEGUID_1
James Walking SOMEFAKEGUID_2
John Running SOMEFAKEGUID_3
John Running SOMEFAKEGUID_3
John Walking SOMEFAKEGUID_4
Notice how a new GUID is created for each matching pair. So the James/Running combo has the same GUID for all James/Running combos... and the John/Running also has the same GUID for the John/Running combos, but not the same GUID as the James/Running combos do.
I tried to make that as clear as possible, but hopefully that isn't clear as mud!
Can someone show me what the SQL query would look like in order to update that temp table with the correct GUIDs?
Thanks in advance.
Ryan
Using NEWID() seems to be a pain. Using it a CTE creates a sperate ID, so you need some intermediary table instead.
Declare #Table as table (name varchar(20), activity varchar(20) , SpecialID uniqueidentifier)
Declare #DistinctTable as table (name varchar(20), activity varchar(20) , SpecialID uniqueidentifier)
INSERT INTO #Table
(name, activity)
values
('James','Running'),
('James','Running'),
('James','Walking'),
('John','Running'),
('John','Running'),
('John','Walking')
WITH distinctt
AS (SELECT DISTINCT name,
activity
FROM #Table)
INSERT INTO #DistinctTable
SELECT name,
activity,
Newid()
FROM distinctt
UPDATE #Table
SET specialid = dt.specialid
FROM #Table t
INNER JOIN #DistinctTable dt
ON t.activity = dt.activity
AND t.name = dt.name
SELECT * FROM #Table
Produces
name activity SpecialID
-------------------- -------------------- ------------------------------------
James Running AAA22BC5-51FE-43B3-8CC9-4C4A5B4CC981
James Running AAA22BC5-51FE-43B3-8CC9-4C4A5B4CC981
James Walking 1722B76B-5F17-4931-8D7C-2ECADB5A4DFD
John Running FBC1F86B-592D-4D30-ACB3-80DA26B00900
John Running FBC1F86B-592D-4D30-ACB3-80DA26B00900
John Walking 84282844-AAFD-45CA-9218-F7933E5102C6
I'm sure there are better ways to do this, but you can try the following:
WITH TableId AS
(
SELECT DISTINCT Name, Activity
FROM YourTable
)
UPDATE A
SET A.SpecialId = B.SpecialId
FROM YourTable A
INNER JOIN (SELECT Name, Activity, NEWID() SpecialId FROM TableId) B
ON A.Name = B.Name AND A.Activity = B.Activity
Well, I know that you're not using mySQL, but this is how it would work in mySQL (tested)
update temp_table, (
select uuid() as spec_key, name, activity from (
select distinct name, activity from temp_table) as anotherTemp) as anotheranotherTemp
set specialID = anotheranotherTemp.spec_key
where temp_table.Activity = anotheranotherTemp.activity
and temp_table.Name = anotheranotherTemp.name;
It LOOKS like this would work in SQL 2008 (not-tested)
MERGE INTO temp_table AS tt
USING (
select newId() as spec_key, name, activity from (
select distinct name, activity from temp_table) as anotherTemp
ON anotherTemp.activity = tt.activity
and anotherTemp.name = tt.name
WHEN MATCHED
THEN UPDATE
SET specialID = anotherTemp.spec_key;
Performance would not be good though.
I agree with #ConradFrix to use NEWID() first, Lamak script should be modified as mentioned below. It's working fine for me. Thanks for all.
WITH TableId AS
(
SELECT DISTINCT Name, Activity, NEWID() SpecialId
FROM YourTable
)
UPDATE A
SET A.SpecialId = B.SpecialId
FROM YourTable A
LEFT JOIN (SELECT Name, Activity, SpecialId FROM TableId) B
ON A.Name = B.Name AND A.Activity = B.Activity