I have 2 tables on SQL Server 2008, each one has a single column and the same rows count number:
USERS OPERATION
Name Operation
----------- -----------
John W383
William R823
Karen X933
Peter M954
Alex S744
I need to perform every week a random draw between the 2 tables to get something like the follow and save it into a 3rd. table:
DRAW_RESULT:
Name Operation_Assigned Week_Number
----------------------------------------------
Peter M954 2
William W383 2
John S744 2
Alex X933 2
Karen R823 2
Name Operation_Assigned Week_Number
----------------------------------------------
William R823 3
Alex M954 3
Karen X933 3
John S744 3
Peter W383 3
How can I do this using T-SQL?
If I understood correctly what you're doing, something like this should work:
select name, operation from (
select
row_number() over (order by (select null)) as RN,
name
from
users
) U join (
select
row_number() over (order by newid()) as RN,
operation
from
operation
) O on U.RN = O.RN
Edit: row_number with newid() works, so removed the extra derived table.
Here's also SQL Fiddle to test this.
Related
Lets say I have a table in SQLServer named Tasks. It contains some tasks with people assigned to tasks. Workers are in one column. They are separated by semicolon.
ID Workers
1 John Newman; Troy Batchelor; Mike Smith
2 Chris Portman
3 Sara Oldman; Greg House
I need to separate workers from column like below
The result:
ID Worker
1 John Newman
1 Troy Batchelor
1 Mike Smith
2 Chris Portman
3 Sara Oldman
3 Greg House
I have no idea what to do.
Do I have to use some procedure or simple query is enough?
i solved your problem without using any function or stored procedure
SELECT ID,Workers FROM tblSemiColon
SELECT ID,
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Workers
FROM
(
SELECT ID,CAST('<XMLRoot><RowData>' + REPLACE(Workers,';','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM tblSemiColon
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
this will work across all the version of sql server..i had tested it....
you can reduce the size of varchar length..
If you are on sql-server 2016 or higher you can use STRING_SPLIT function
SELECT id, value
FROM Tasks
CROSS APPLY STRING_SPLIT(Workers, ';')
I have a basic SQL Server delete script that goes:
Delete from tableX
where colA = ? and colB = ?;
In tableX, I do not have any columns indicating sequential IDs or timestamp; just varchar. I want to delete the latest entry that was inserted, and I do not have access to the row number from the insert script. TOP is not an option because it's random. Also, this particular table does not have a primary key, and it's not a matter of poor design. Is there any way I can do this? I recall mysql being able to call something like max(row_number) and also something along the lines of limit one.
ROW_NUMBER exists in SQL Server, too, but it must be used with an OVER (order_by_clause). So... in your case it's impossible for you unless you come up with another sorting algo.
MSDN
Edit: (Examples for George from MSDN ... I'm afraid his company has a Firewall rule that blocks MSDN)
SQL-Code
USE AdventureWorks2012;
GO
SELECT ROW_NUMBER() OVER(ORDER BY SalesYTD DESC) AS Row,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0;
Output
Row FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
Returning a subset of rows
USE AdventureWorks2012;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate, RowNumber
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
Using ROW_NUMBER() with PARTITION
USE AdventureWorks2012;
GO
SELECT FirstName, LastName, TerritoryName, ROUND(SalesYTD,2,1),
ROW_NUMBER() OVER(PARTITION BY TerritoryName ORDER BY SalesYTD DESC) AS Row
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0
ORDER BY TerritoryName;
Output
FirstName LastName TerritoryName SalesYTD Row
--------- -------------------- ------------------ ------------ ---
Lynn Tsoflias Australia 1421810.92 1
José Saraiva Canada 2604540.71 1
Garrett Vargas Canada 1453719.46 2
Jillian Carson Central 3189418.36 1
Ranjit Varkey Chudukatil France 3121616.32 1
Rachel Valdez Germany 1827066.71 1
Michael Blythe Northeast 3763178.17 1
Tete Mensa-Annan Northwest 1576562.19 1
David Campbell Northwest 1573012.93 2
Pamela Ansman-Wolfe Northwest 1352577.13 3
Tsvi Reiter Southeast 2315185.61 1
Linda Mitchell Southwest 4251368.54 1
Shu Ito Southwest 2458535.61 2
Jae Pak United Kingdom 4116871.22 1
Your current table design does not allow you to determine the latest entry. YOu have no field to sort on to indicate which record was added last.
You need to redesign or pull that information from the audit tables. If you have a database without audit tables, you might have to find a tool to read the transaction logs and it will be a very time-consuming and expensive process. Or if you know the date the records you want to remove were added, you could possibly use a backup from just before this happened to find the records that were added. Just be awwre that you might be looking at records changed after this date that you want to keep.
If you need to do this on a regular basis instead of one-time to fix some bad data, then you need to properly design your database to include an identity field and possibly a dateupdated field (maintained through a trigger) or audit tables. (In my opinion no database containing information your company is depending on should be without audit tables, one of the many reasons why you should never allow an ORM to desgn a database, but I digress.) If you need to know the order records were added to a table, it is your responsiblity as the developer to create that structure. Databases only store what is deisnged for tehm to store, if you didn't design it in, then it is not available easily or at all
If (colA +'_'+ colB) can not be dublicate try this.
declare #delColumn nvarchar(250)
set #delColumn = (select top 1 DeleteColumn from (
select (colA +'_'+ colB) as DeleteColumn ,
ROW_NUMBER() OVER(ORDER BY colA DESC) as Id from tableX
)b
order by Id desc
)
delete from tableX where (colA +'_'+ colB) =#delColumn
I need ROW_NUMBER to assign data to a specific user if a condition is met.
ROW_NUMBER will increment normally until a duplicate value is found. When the duplicate value is found, I need it to use the same ROW_NUMBER until a new value is found.
For instance...
When using
SELECT ROW_NUMBER() OVER (ORDER BY COMPANY) AS rownum
,Company
,Contact
FROM TABLE
We can obviously expect this result
rownum Company Contact
1 BOB'S BURGERS BOB
2 STEVE'S SARDINES STEVE
3 STEVE'S SARDINES JERRY
4 STEVE'S SARDINES MARY
5 LARRY's LOBSTER LARRY
6 CHRIS' COWS CHRIS
What I'm trying to get is this. Whenever the Company name doesn't change, repeat the ROW_NUMBER and continue to increment the number when the company does change
rownum Company Contact
1 BOB'S BURGERS BOB
2 STEVE'S SARDINES STEVE
2 STEVE'S SARDINES JERRY
2 STEVE'S SARDINES MARY
3 LARRY'S LOBSTER LARRY
4 CHRIS' COWS CHRIS
I'm using this condition to see if the company matches the previous company name. It returns a 2 if the condition is true
ROW_NUMBER() OVER (PARTITION BY COMPANY ORDER BY COMPANY) AS SameCompany
You want DENSE_RANK not ROW_NUMBER. Try this:
SELECT DENSE_RANK() OVER (ORDER BY COMPANY) AS rownum
,Company
,Contact
FROM TABLE
I've been approaching a problem perhaps in the wrong way. I've researched pivot examples
http://www.codeproject.com/Tips/500811/Simple-Way-To-Use-Pivot-In-SQL-Query
How to create a pivot query in sql server without aggregate function
but they aren't the type I'm looking for.. or perhaps I'm approaching this in the wrong way, and I'm new to sql server.
I want to transform:
Student:
studid | firstname | lastname | school
-----------------------------------------
1 mike lee harvard
1 mike lee ucdavis
1 mike lee sfsu
2 peter pan chico
2 peter pan ulloa
3 peter smith ucb
Desired output: (note for school, want only 3 columns max.)
studid| firstname | lastname | school1 | school2 | school3
---------------------------------------------------------------------
1 mike lee Harvard ucdavis sfsu
2 peter pan chico ulloa
3 peter smith ucb
The tutorials I see shows the use of Sum() , count() ... but I have no idea how to pivot string values of one column and put them into three columns.
You can get the results you desire by taking max(school) for each pivot value. I'm guessing the pivot value you want is rank over school partitioned by student. This would be the query for that:
select * from
(select *, rank() over (partition by studid order by school) rank from student) r
pivot (max(school) for rank in ([1],[2],[3])) pv
note that max doesn't actually do anything. the query would return the same results if you replaced it with min. just the pivot syntax requires the use of an aggregate function here.
SQL Server 2000. Single table has a list of users that includes a unique user ID and a non-unique user name.
I want to search the table and list out any users that share the same non-unique user name. For example, my table looks like this:
ID User Name Name
== ========= ====
0 parker Peter Parker
1 parker Mary Jane Parker
2 heroman Joseph (Joey) Carter Jones
3 thehulk Bruce Banner
What I want to do is do a SELECT and have the result set be:
ID User Name Name
== ========= ====
0 parker Peter Parker
1 parker Mary Jane Parker
from my table.
I'm not a T-SQL guru. I can do the basic joins and such, but I'm thinking there must be an elegant way of doing this. Barring elegance, there must be ANY way of doing this.
I appreciate any methods that you can help me with on this topic. Thanks!
---Dan---
One way
select t1.* from Table t1
join(
select username from Table
group by username
having count(username) >1) t2 on t1.username = t2.username
The simplest way I can think of to do this uses a sub-query:
select * from username un1 where exists
(select null from username un2
where un1.user_name = un2.user_name and un1.id <> un2.id);
The sub-query selects all names that have >1 row with that name... outer query selects all the rows matching those IDs.
SELECT T.*
FROM T
, (SELECT Dupe_candidates.USERNAME
FROM T AS Dupe_candidates
GROUP BY Dupe_candidates.USERNAME
HAVING count(*)>1
) Dupes
WHERE T.USERNAME=Dupes.USERNAME
You can try the following:
SELECT *
FROM dbo.Person as p1
WHERE
(SELECT COUNT(*) FROM dbo.Person AS p2 WHERE p2.UserName = p1.UserName) > 1;