问题
I managed to create a simple query that selects a random first and last name and inserts them into a result table. I wanted to create something I could interchange with the various tests I run where I have to manufacture a lot of data. Here is the code (I only included 5 first and last names each for simplicity purposes):
SELECT
FirstName, LastName
FROM
(SELECT TOP 1
FirstName
FROM
(SELECT 'John' AS FirstName
UNION SELECT 'Tim' AS FirstName
UNION SELECT 'Laura' AS FirstName
UNION SELECT 'Jeff' AS FirstName
UNION SELECT 'Sara' AS FirstName) AS First_Names
ORDER BY NEWID()) n1
FULL OUTER JOIN
(SELECT TOP 1
LastName
FROM (SELECT 'Johnson' AS LastName
UNION SELECT 'Hudson' AS LastName
UNION SELECT 'Jackson' AS LastName
UNION SELECT 'Ranallo' AS LastName
UNION SELECT 'Curry' AS LastName) AS Last_Names
ORDER BY NEWID()) n2 ON [n1].FirstName = [n2].LastName
WHERE
n1.FirstName IS NOT NULL OR n2.LastName IS NOT NULL
Here are the results:
FirstName LastName
NULL Hudson
John NULL
I want the results to return one row with a first and last name randomly generated so that each row would have a complete name (no NULL values). I'm sure it's something simple I am overlooking.
回答1:
The following code will allow you to generate a series of random names, where a cross join solution allows only one at a time. Not sure if you need to do this more than once, but if you do:
create table #table (firstname varchar(50), lastname varchar(50))
declare @counter int = 1
declare @max int = 5 --set number of repetitions here
declare @a varchar(50)
declare @b varchar(50)
while @counter <= @max
begin
SET @a = (SELECT TOP 1 FirstName
FROM (SELECT 'John' AS FirstName
UNION SELECT 'Tim' AS FirstName
UNION SELECT 'Laura' AS FirstName
UNION SELECT 'Jeff' AS FirstName
UNION SELECT 'Sara' AS FirstName) AS First_Names ORDER BY NEWID())
SET @b =
(SELECT TOP 1 LastName
FROM (SELECT 'Johnson' AS LastName
UNION SELECT 'Hudson' AS LastName
UNION SELECT 'Jackson' AS LastName
UNION SELECT 'Ranallo' AS LastName
UNION SELECT 'Curry' AS LastName) AS Last_Names ORDER BY NEWID())
insert into #table values (@a, @b)
set @counter = @counter + 1
end
select * from #table
回答2:
The problem is your join. This is how you can do it:
SELECT FirstName, LastName
FROM
(SELECT TOP 1 FirstName
FROM (SELECT 'John' AS FirstName
UNION SELECT 'Tim' AS FirstName
UNION SELECT 'Laura' AS FirstName
UNION SELECT 'Jeff' AS FirstName
UNION SELECT 'Sara' AS FirstName) AS First_Names ORDER BY NEWID())n1
CROSS JOIN
(SELECT TOP 1 LastName
FROM (SELECT 'Johnson' AS LastName
UNION SELECT 'Hudson' AS LastName
UNION SELECT 'Jackson' AS LastName
UNION SELECT 'Ranallo' AS LastName
UNION SELECT 'Curry' AS LastName) AS Last_Names ORDER BY NEWID())n2
回答3:
If you need to get more than 1 combination here is an alternative to using a loop for this type of thing.
declare @max int = 5;
with FirstNames(FName) as
(
SELECT 'John' UNION ALL
SELECT 'Tim' UNION ALL
SELECT 'Laura' UNION ALL
SELECT 'Jeff' UNION ALL
SELECT 'Sara'
)
, LastNames(LName) as
(
SELECT 'Johnson' UNION ALL
SELECT 'Hudson' UNION ALL
SELECT 'Jackson' UNION ALL
SELECT 'Ranallo' UNION ALL
SELECT 'Curry'
)
, SortedNames(FName, LName, RowNum) as
(
select FName
, LName
, ROW_NUMBER() over (Order by newid())
from FirstNames
cross join LastNames
)
select FName
, LName
from SortedNames
where RowNum <= @max
order by NEWID();
回答4:
If you are wanting to efficiently generate multiple rows (you did mention needing to generate a lot of sample data), then here is something I just posted earlier today on another question on S.O. ( Msg 6522, Level 16 warning during execution of clr stored procedure ). That question dealt with randomizing 4 fields instead of just two, but I am keeping those extra fields here so you can see how easy it is to adapt to other scenarios you might have. It is rather simple to remove any of the fields, and it is also easy to add new values to any of the 4 table variables (to increase the number of possible combinations) as the query dynamically adjusts the randomization range to fit whatever data is in each table variable (i.e. rows 1 - n).
DECLARE @TelNumber TABLE (TelNumberID INT NOT NULL IDENTITY(1, 1),
Num VARCHAR(30) NOT NULL);
INSERT INTO @TelNumber (Num) VALUES ('1525407'), ('5423986'), ('1245398'), ('32657891'),
('123658974'), ('7896534'), ('12354698');
DECLARE @FirstName TABLE (FirstNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @FirstName (Name) VALUES ('Babak'), ('Carolin'), ('Martin'), ('Marie'),
('Susane'), ('Michail'), ('Ramona'), ('Ulf'), ('Dirk'), ('Sebastian');
DECLARE @LastName TABLE (LastNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @LastName (Name) VALUES ('Bastan'), ('Krause'), ('Rosner'),
('Gartenmeister'), ('Rentsch'), ('Benn'), ('Kycik'), ('Leuoth'),
('Kamkar'), ('Kolaee');
DECLARE @Address TABLE (AddressID INT NOT NULL IDENTITY(1, 1),
Addr NVARCHAR(100) NOT NULL);
INSERT INTO @Address (Addr) VALUES ('Deutschlan Chemnitz Sonnenstraße 59'), (''),
('Deutschland Chemnitz Arthur-Strobel straße 124'),
('Deutschland Chemnitz Brückenstraße 3'),
('Iran Shiraz Chamran Blvd, Niayesh straße Nr.155'), (''),
('Deutschland Berlin Charlotenburg Pudbulesky Alleee 52'),
('United State of America Washington DC. Farbod Alle'), ('');
DECLARE @RowsToInsert INT = 10000;
;WITH rowcounts AS
(
SELECT (SELECT COUNT(*) FROM @TelNumber) AS [TelNumberRows],
(SELECT COUNT(*) FROM @FirstName) AS [FirstNameRows],
(SELECT COUNT(*) FROM @LastName) AS [LastNameRows],
(SELECT COUNT(*) FROM @Address) AS [AddressRows]
), nums AS
(
SELECT TOP (@RowsToInsert)
(CRYPT_GEN_RANDOM(1) % rc.TelNumberRows) + 1 AS [RandomTelNumberID],
(CRYPT_GEN_RANDOM(1) % rc.FirstNameRows) + 1 AS [RandomFirstNameID],
(CRYPT_GEN_RANDOM(1) % rc.LastNameRows) + 1 AS [RandomLastNameID],
(CRYPT_GEN_RANDOM(1) % rc.AddressRows) + 1 AS [RandomAddressID]
FROM rowcounts rc
CROSS JOIN msdb.sys.all_columns sac1
CROSS JOIN msdb.sys.all_columns sac2
)
-- INSERT dbo.Unsprstb(Firstname, Lastname, Tel, Address)
SELECT fn.Name, ln.Name, tn.Num, ad.Addr
FROM @FirstName fn
FULL JOIN nums
ON nums.RandomFirstNameID = fn.FirstNameID
FULL JOIN @LastName ln
ON ln.LastNameID = nums.RandomLastNameID
FULL JOIN @TelNumber tn
ON tn.TelNumberID = nums.RandomTelNumberID
FULL JOIN @Address ad
ON ad.AddressID = nums.RandomAddressID;
Notes:
- The
FULL JOIN
s are needed instead ofINNER JOIN
s to get the entire@RowsToInsert
amount of rows. - Duplicate rows are possible due to the very nature of this randomization AND not filtering them out by using
DISTINCT
. However,DISTINCT
cannot be used with the given sample data in the question since the number of elements in each array / table variable provide for only 6300 unique combinations and the requested number of rows to generate is 10,000. If more values are added to the table variables such that the total possible unique combinations rises above the requested number of rows, then either theDISTINCT
keyword can be added to thenums
CTE, or the query can be restructured to simplyCROSS JOIN
all of the table variable, include aROW_COUNT()
field, and grab theTOP(n)
usingORDER BY NEWID()
(but that approach has its pros and cons as well). - The
INSERT
is commented out so it is easier to see that the query above produces the desired result. Just uncomment theINSERT
to have the query do the actual DML operation.
来源:https://stackoverflow.com/questions/31948717/sql-random-name-generator-not-inserting-first-and-last-name-in-the-same-row