Rows in columns - sql-server-2000

I have this table:
Id Kind
1 MODEL
1 MOTOR
2 MODEL
2 MOTOR
3 MOTOR
4 MODEL
And I want to insert into anothe table:
IdModel IdMotor
1 1
1 2
1 3
2 1
2 2
2 3
4 1
4 2
4 3
I know how to do it with cursors, but it's indeed very slow. I've tried with union but it looks like today is not my best day!
I also know this can be done in SQL 2005 with pivot, but I have to do it with SQL Server 2000.
Any Transact-SQL guru out there with a good and quick query?
Thanks in advance!

Looks like this will work:
INSERT Table2
SELECT model.id, motor.id
FROM
Table model,
Table motor
WHERE
model.Kind = 'MODEL'
and motor.Kind = 'MOTOR'

INSERT INTO AnotherTable
SELECT [IdModel]
, [IdMotor]
FROM (
SELECT [IdModel] = ID
FROM ATable
WHERE Kind = 'MODEL'
) md
CROSS APPLY
(
SELECT [IdMotor] = ID
FROM ATable
WHERE Kind = 'MOTOR'
) mt

Related

Finding duplicate **Set of Values** in multiple rows in SQL Server table

I have a SQL Server database table with this sample data:
ProductID GenericID MG
---------------------------------
1 1 2g
1 2 5g
2 2 5g
3 1 2g
3 2 5g
4 1 2g
5 1 2g
5 3 7g
6 2 5g
7 1 2g
8 1 2g
I want to find out the query to select data
if I select ProductID=1 then the query should check what GenericID are associated with ProductID=1
In above data case if user select ProductID=1 then query will check GenericID=1 and 2 are associated with ProductID=1.
Then after I want to go through all rows and select those rows who has the same Unique ProductID and also having only GenericID=1 and 2.
as in above case the final output will be as shown below....
I select ProductID=1 and output has four rows, because only ProductId 3 has same GenericID as were of ProductId=1.
If I select only ProductId=1 then I want to get all the rows with the same exact set of GenericID values as ProductID=1, which is the set { 1, 2 } in my sample data. I am struggling with the query logic.
For example - I select ProductID=1, this is the output that I want is as follows, because ProductID 3 has the same set of GenericID values as ProductID 1.
ProductID GenericID MG
-------------------------------
1 1 2g
1 2 5g
3 1 2g
3 2 5g
GenericID can be on or multiple dynamic values.
Another example - if I select ProductID=7, this is the output I want:
In this example - It will only get those results that are having only GenericID=1 because ProductID=7 has only GenericID=1. any set of productID which is having GenericID=1 and also that set includes other GenericID will be neglected.
ProductID GenericID MG
------------------------------
7 1 2g
8 1 2g
4 1 2g
I need to find out the query to select the required output.
I want all of the products that have the same set of generic id's as the predicate product.
The simplest method is probably to use string_agg():
with t as (
select productID, string_agg(genericId, ',') within group (order by genericId) as genericIds
from sample
group by productID
)
select s.*
from t join
t t2
on t.genericIds = t2.genericIds and t2.productId = 1 join
sample s
on s.productId = t.productId;
Gordon, thanks a lot for your prompt response, basically I forget to inform you that I am using SQL 2014 and that's why string_agg(): action function wasn't helpful for me but I really appreciate your help and the prompt response that make my day. Here I created my query with the help of your other query and you became and very helpful resource for me.
select PG.PID2 as Alternatives
from (select d1.ProductID as PID1, d2.ProductID as PID2
from (select distinct ProductID from ProductsGenerics Where ProductID=#PID) d1 cross join
(select distinct ProductID from ProductsGenerics) d2
) PG left outer join
ProductsGenerics e1
on e1.ProductID = PG.PID1 full outer join
ProductsGenerics e2
on PG.PID2 = e2.ProductID and e1.genericid = e2.GenericID-- and e1.MG = e2.MG
group by PG.PID1, PG.PID2
having SUM(case when e1.GenericID is null then 1 else 0 end) = 0 and
SUM(case when e2.GenericID is null then 1 else 0 end) = 0

Create multiple rows based on 1 column

I currently have a table with a quantity in it.
ID Code Quantity
1 A 1
2 B 3
3 C 2
4 D 1
Is there anyway to write a sql statement that would get me
ID Code Quantity
1 A 1
2 B 1
2 B 1
2 B 1
3 C 1
3 C 1
4 D 1
I need to break out the quantity and have that many number of rows
Thanks
Here's one option using a numbers table to join to:
with numberstable as (
select 1 AS Number
union all
select Number + 1 from numberstable where Number<100
)
select t.id, t.code, 1
from yourtable t
join numberstable n on t.quantity >= n.number
order by t.id
Online Demo
Please note, depending on which database you are using, this may not be the correct approach to creating the numbers table. This works in most databases supporting common table expressions. But the key to the answer is the join and the on criteria.
One way would be to generate an array with X elements (where X is the quantity). So for rows
ID Code Quantity
1 A 1
2 B 3
3 C 2
you would get
ID Code Quantity ArrayVar
1 A 1 [1]
2 B 3 [1,2,3]
3 C 2 [2]
using a sequence function (e.g, in PrestoDB, sequence(start, stop) -> array(bigint))
Then, unnest the array, so for each ID, you get a X rows, and set the quantity to 1. Not sure what SQL distribution you're using, but this should work!
You can use connect by statement to cross join tables in order to get your desired output.
check my solution it works pretty robust.
select
"ID",
"Code",
1 QUANTITY
from Table1, table(cast(multiset
(select level from dual
connect by level <= Table1."Quantity") as sys.OdciNumberList));

Is there a way to update groups of rows with separate incrementing values in one query

Lets say you have the following table:
Id Index
1 3
1 1
2 1
3 3
1 5
what I would like to have is the following:
Id Index
1 0
1 1
2 0
3 0
1 2
As you might notice, the goal is for every row where Id is the same, to incrementally update the Index column, starting from zero.
Now, I know this is fairly simple with using cursors, but out of curiosity is there a way to do this with single UPDATE query, somehow combining with temp tables, common table expressions or something similar?
Yes, assuming that the you don't really care about the order of the values for the new index values. SQL Server offers updatable CTEs and window functions that do exactly what you want:
with toupdate as (
select t.*, row_number() over (partition by id order by (select NULL)) as newindex
from table t
)
update toupdate
set index = newindex;
If you want them in a specific order, then you need another column to specify the ordering. The existing index column doesn't work.
With Row_number() -1 and CTE you can write as:
CREATE TABLE #temp1(
Id int,
[Index] int)
INSERT INTO #temp1 VALUES (1,3),(1,1),(2,1),(3,3),(1,5);
--select * from #temp1;
With CTE as
(
select t.*, row_number() over (partition by id order by (select null))-1 as newindex
from #temp1 t
)
Update CTE
set [Index] = newindex;
select * from #temp1;
Demo
I'm not sure why you would want to do this really, but I had fun figuring it out!
This solution relies on your table having a primary key for the self join... but you could always create an auto inc index if none exists and this is a one off job... This will also have the added benefit of getting you to think about the precise ordering of this you want... as currently there is no way of saying which order [ID] will get [Index] in.
UPDATE dbo.Example
SET [Index] = b.newIndex
FROM dbo.Example a
INNER JOIN (
select
z.ID,
z.[Index],
(row_number() over (partition by ID order by (select NULL))) as newIndex
from Example z
) b ON a.ID = b.ID AND a.[Index]=b.[Index] --Is this a unique self join for your table?.. no PK provided. You might need to make an index first.
Probably, this is what you want
SELECT *,RANK() OVER(PARTITION BY Id ORDER BY [Index])-1 AS NewIndex FROM
(
SELECT 1 AS Id,3 [Index]
UNION
SELECT 1,1
UNION
SELECT 2,1
UNION
SELECT 3,3
UNION
SELECT 1,5
) AS T
& the result will come as
Now if you want to update the table then execute this script
UPDATE tblname SET Index=RANK() OVER(PARTITION BY t.Id ORDER BY t.[Index])-1
FROM tblname AS t
In case I am missing something or any further assistance is required please let me know.
CREATE TABLE #temp1(
Id int,
Value int)
INSERT INTO #temp1 VALUES (1,2),(1,3),(2,3),(4,5)
SELECT
Id
,Value
,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Id) Id
FROM #temp1
Start with this :)
Gave me results like
Id Value Count
1 2 1
1 3 2
1 2 3
1 3 4
1 2 5
1 3 6
1 2 7
1 3 8
2 3 1
2 4 2
2 5 3
2 3 4
2 4 5
2 5 6
2 4 7
2 5 8
2 3 9
2 3 10
3 4 1
4 5 1
4 5 2
4 5 3
4 5 4

Replace for-loop in SQL

I have a table in a database. For example table of user IDs and right IDs:
UserId RightId
---------------
1 1
1 2
1 3
2 1
2 2
3 1
3 2
3 3
4 1
4 2
5 1
6 1
6 2
What is the best way to insert for each userId new rightId 4?
I heard that using while or for loops is not the best way to do such thing.
Can you please show me an example how to solve such problem with JOINs and SETs for example?
How about something like
INSERT INTO MyTable (UserID, RightID)
SELECT DISTINCT
UserID,
4
FROM MyTable
SQL Fiddle DEMO
If you simply want to change every entry in the RightId column you could try something like this:
UPDATE <table_name> SET RightId=4;

Difficulty in creating update totals query on same table

Consider the following table:
ID nonUniqueID value total
--------------------------
1 12345 5 x
2 12345 10 x
3 789 20 x
4 789 5 x
I need to make a query something like this (psuedo SQL), which will work within Access 2007:
UPDATE table
SET total = SUM(value)
WHERE nonUniqueID IS SAME;
The result should be as follows:
ID nonUniqueID value total
--------------------------
1 12345 5 15
2 12345 10 15
3 789 20 25
4 789 5 25
I've tried group bys, but I got odd results that quite frankly, I could not interpret. Does anybody know how I could achieve something like this?
Not sure if this works in Access or not, but give it a try:
update table t1
inner join (
select nonUniqueID, sum(value) as SumValue
from table
group by nonUniqueID
) t2 on t1.nonUniqueID = t2.nonUniqueID
set t1.total = t2.SumValue
Update: Based on this question, it looks like it is not going to work. But give it a shot! If it doesn't, you can use the approach suggested in that question.
Another possible option:
update t
set total = (select SUM(value) from table where nonUniqueID = t.nonUniqueID)
from table t