how to get combination of rows through query - sql

I have a table with following fields and data.
id type value
1 1 1
2 2 1
3 2 2
4 2 3
After running the query I should get result in temp table like below
1,1
1,2
1,3
and if i have multiple value in type 1 then it should do the same
so if the data is
id type value
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
I should get result
1,1
1,2
1,3
2,1
2,2
2,3
Appreciate any help on this.

That looks like:
SELECT t1.value, t2.value
FROM table t1
JOIN table t2
ON t1.type = 1
AND t2.type = 2
;
which can also be written as:
SELECT t1.value, t2.value
FROM ( SELECT value FROM table WHERE type = 1 ) t1
CROSS
JOIN ( SELECT value FROM table WHERE type = 2 ) t2
;
(The former is simpler, but the latter makes clearer that this is semantically a CROSS JOIN, since the join doesn't actually depend on any relationship between the joined records.)

SELECT ISNULL(CAST([type] as varchar(20)), '')
+ ','
+ ISNULL(CAST([value] as varchar(20)), '')
AS CommaSeparated
FROM types

Related

SQL only join when key matches one criteria

I have two tables that look like the following:
Table 1 (IDs):
ID
1
2
3
4
5
Table 2 (Categories):
ID CAT
1 A
1 B
2 A
3 A
4 B
5 A
5 B
5 C
What I would like to do is join table 2 to table 1 and only keep instances where there is 1) Only one match 2) That match is CAT = A
So my final table would look like:
ID CAT
2 A
3 A
One method is aggregation and having:
select id, max(cat)
from t
group by id
having count(*) = 1 and
max(cat) = 'A';
You can use a subquery with not exists:
select t1.id, t2.cat
from table1 t1
join table2 t2 on t1.id = t2.id
where t2.cat = 'A' and not exists (select 1 from table2 t3 where t3.id = t1.id and t3.cat != 'A');
Output:
id
cat
2
A
3
A

Split one row to many in same database table

We have a requirement where we want to split one row to many rows ( in the same table ) based on some conditions.
Let's suppose we have this table :
ID
Value
1
V1
2
V2
3
V3
Requirement is,
if ID=1, split this row into two more rows where IDs of new rows will be 4 and 5 and the value will be V1 (same as ID = 1 value) only.
if ID=2, don't split.
if ID=3, split this row into one more row where ID of the new row will be 6 and value will be V3 (same as ID = 3 value) only.
The final o/p will be :
ID
Value
1
V1
4
V1
5
V1
2
V2
3
V3
6
V3
I am looking out for some SQL script/Stored Proc that will help me in achieving the same.
You can generate the rows with a join and derived table . . . and then use union all to bring in the existing rows:
select id, value
from t
union all
select x.new_id, t.value
from t join
(select 1 as old_id, 4 as new_id from dual union all
select 1 as old_id, 5 as new_id from dual union all
select 3 as old_id, 6 as new_id from dual
) x
on t.id = x.old_id;
If you just want to insert the values, use insert with the second query.
You can join your table with numbers as follows:
select case when t.id = 2 then t.id
when t.id = 3 then t.id * lvl
when t.id = 1 and lvl > 1 then lvl+2
else lvl
end as id, t.value
from your_table t
cross join (select level as lvl from dual connect by level <=3)
where t.id = 1 or (t.id=2 and lvl=1) or (t.id = 3 and lvl <= 2)

SQL Group by fixed list of values

If I have two columns:
col1 col2 amount
1 2 15
2 3 12
1 3 10
3 1 4
3 2 3
And I perform a group by col1,col2 then I get a row for each combination (present) in the data.
My problem though is, that I dont always have all combinations, but I would want to return a row of each combination still. So if there isn't a combination. for example 2 -> 1 then I would want its value to be 0.
Can I somehow specify the "levels" of the group by?
I'm using SQL Oracle.
and the outcome I would want is:
1 -> 2 15
1 -> 3 10
2 -> 1 0
2 -> 3 12
3 -> 1 4
3 -> 2 3
With their respective amount, and 0 if they dont exist, or null works. ( I have a filter to exclude where col1 and col2 are same)
Generate all the rows using cross join and then filter for the ones you want:
select c1.col1, c2.col2, coalesce(t.amount, 0)
from (select 1 as co1l from dual union all
select 2 as co1l from dual union all
select 3 as co1l from dual
) c1 cross join
(select 1 as co12 from dual union all
select 2 as co12 from dual union all
select 3 as co12 from dual
) c2 left join
t
on t.col1 = c1.col1 and t.col2 = c2.col2
where c1.col1 <> c2.col2;

require to form a sql query

I was working on preparing a query where I was stuck.
Consider tables below:
table1
id key col1
-- --- -----
1 1 abc
2 2 d
3 3 s
4 4 xyz
table2
id col1 foreignkey
-- ---- ----------
1 12 1
2 13 1
3 14 1
4 12 2
5 13 2
Now what I need is to select only those records from table1 for which the corresponding entries in table2 does not have say col1 value as 12.
So the challenge is after applying join even though it will skip for value 1 corresponding to col1 equal to 12 it still has another multiple rows whose values are say 13, 14 for which also they have same foreignkey. Now what I want is if there is a single row having value 12 then it should not pick that id at all from table1.
How can I form a query with this?
The output which i need is say from above table structure i want to get those records from table1 for which col1 value from table2 does not have value as 14.
so my query should return me only row 2 from table1 and not row 1.
Another way of doing that. The first two queries are just for making the sample data.
;WITH t1(id ,[key] ,col1) AS
(
SELECT 1 , 1 , 'abc' UNION ALL
SELECT 2 , 2 , 'd' UNION ALL
SELECT 3 , 3 , 's' UNION ALL
SELECT 4 , 4 , 'xyz'
)
,t2(id ,col1, foreignkey) AS
(
SELECT 1 , 12 , 1 UNION ALL
SELECT 2 , 13 , 1 UNION ALL
SELECT 3 , 14 , 1 UNION ALL
SELECT 4 ,12 , 2 UNION ALL
SELECT 5 ,13 , 2
)
SELECT id, [key], col1
FROM t1
WHERE id NOT IN (SELECT t2.Id
FROM t2
INNER JOIN t1 ON t1.Id = t2.foreignkey
WHERE t2.col1 = 14)
This is a typical case for NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE NOT EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id AND t2.col1 = 14)
The above query will not select a row from table1 if there is a single correlated row in table2 having col1 = 14.
Output:
id key col1
-------------
2 2 d
3 3 s
4 4 xyz
If you want to return records that, in addition to the criterion set above, also have correlated records in table2, then you can use the following query:
SELECT t1.id, MAX(t1.[key]) AS [key], MAX(t1.col1) AS col1
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.foreignkey
GROUP BY t1.id
HAVING COUNT(CASE WHEN t2.col1 = 14 THEN 1 END) = 0
Output:
id key col1
-------------
2 2 d
You can also achieve the same result with the second query using a combination of EXISTS and NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id)
AND
NOT EXISTS (SELECT 1
FROM table2 t3
WHERE t3.foreignkey = t1.id AND t3.col1 = 14)
select t1.id,t1.key,
(select ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1 DESC) AS Row,* into
#Temp from table1)
from table1 t1
inner join table2 t2 on t1.id=t2.foreignkey
where t2.col1=(select col1 from #temp where row>1)

SQL: Making a 'computation row'

I have a table that looks like this
TYPE | A | B | C | ... | Z
one | 4 | 4 | 4 | ... | 4
two | 3 | 2 | 2 | ... | 1
And I wanted to insert a row with a computation (row one minus row two):
TYPE | A | B | C | ... | Z
one | 4 | 4 | 4 | ... | 4
two | 3 | 2 | 2 | ... | 1
delta| 1 | 2 | 2 | ... | 3
I was thinking of a SQL command that looks like
(select A from table where type=one) - (select A from table where type=two)
Down side is, it's too long and I also have to do that for all the columns (A-Z) and that's quite a lot.
I'm sure there's a more elegant way of doing this.
PS:
The sequence of my code looks like this btw:
// I'm inserting the data from a RawTable to a TempTable
INSERT one
INSERT two
INSERT delta
INSERT three
INSERT four
INSERT delta
...
INSERT onehundredone
INSERT onehundredtwo
INSERT delta
I have added an ID column with identity to your temp table. You can use that to figure out what rows should be grouped.
create table YourTable
(
ID int identity primary key,
[TYPE] varchar(20),
A int,
B int,
C int
)
insert into YourTable ([TYPE], A, B, C)
select 'one', 4, 4, 4 union all
select 'two', 3, 2, 2 union all
select 'three', 7, 4, 4 union all
select 'four', 3, 2, 2 union all
select 'five', 8, 4, 4 union all
select 'six', 3, 2, 2
select T.[TYPE], T.A, T.B, T.C
from
(
select
T.ID,
T.[TYPE],
T.A,
T.B,
T.C
from YourTable as T
union all
select
T2.ID,
'delta' as [TYPE],
T1.A-T2.A as A,
T1.B-T2.B as B,
T1.C-T2.C as C
from YourTable as T1
inner join YourTable as T2
on T1.ID = T2.ID-1 and
T2.ID % 2 = 0
) as T
order by T.ID, case T.[TYPE] when 'delta' then 1 else 0 end
Result:
TYPE A B C
-------------------- ----------- ----------- -----------
one 4 4 4
two 3 2 2
delta 1 2 2
three 7 4 4
four 3 2 2
delta 4 2 2
five 8 4 4
six 3 2 2
delta 5 2 2
Sorting on column C from first row in group:
select T.[TYPE], T.A, T.B, T.C
from
(
select
T1.ID,
T1.[TYPE],
case T1.ID % 2 when 1 then T1.C else T2.C end as Sortorder,
T1.A,
T1.B,
T1.C
from YourTable as T1
left outer join YourTable as T2
on T1.ID = T2.ID+1
union all
select
T2.ID,
'delta' as [TYPE],
T1.C as Sortorder,
T1.A-T2.A as A,
T1.B-T2.B as B,
T1.C-T2.C as C
from YourTable as T1
inner join YourTable as T2
on T1.ID = T2.ID-1 and
T2.ID % 2 = 0
) as T
order by T.Sortorder, T.ID, case T.[TYPE] when 'delta' then 1 else 0 end
I'm not aware of any way to do this "easily" (i.e. without having to specify every column), I can't come up with any way to do it easily, so I'll go on the record as saying that it can't be done. Easily.
The non-easy way would be to build dynamic code--something that loops through the database metadata, builds a string containing the statement(s) to execute your desired routine column by column, and then execute that string. You really want to avoid this whenever possible.
One shortcut, if you just need to build a procedure or function that does this (i.e. build once run many), you could copy the list of columns into a spreadsheet (Excel), build out the highly-repetitive statements using forumlas that reference the column names, and then copying the results back. (This is much simpler to do than it is to explain.)
I have no idea why you're doing this, but the way I'd approach it is:
insert into table
select 'delta',
t1.a - t2.a,
t1.b - t2.b
.....
from table t1,
table t2
where t1.type = 'one'
and t2.type = 'two'
You would have to run this query immediately after inserting "one" and "two", then re-run it after inserting "three" and "four". Nasty nasty nasty.
If you can re-name the columns in some way, or create a numerical column, you could run it in a single query.
When you replace one for 1, two for 2, and so on, then maybe this sql could work:
INSERT INTO PodMays
SELECT
"Delta", A.A-B.A, A.B-B.B, A.C-B.C, A.D-B.D, A.E-B.E
FROM
(
SELECT TOP 1
*
FROM
(SELECT TOP 2 * FROM PodMays WHERE Type <> "Delta" ORDER BY Type DESC)
ORDER BY
Type ASC
) AS A,
(
SELECT TOP 1
*
FROM
(SELECT TOP 2 * FROM PodMays WHERE Type <> "Delta" ORDER BY Type DESC)
ORDER BY
Type DESC
) AS B