SQL rotate results from wide to vertical - sql

I would love some help with the best way to capture some column data and rotate it so I can store the column name and numeric value in a temp table.
The results are a single row showing a value for the columns listed here:
AccountingCode ActiveCostAllocationCode1Segment1 ActiveCostAllocationCode1Segment1Description
-------------- --------------------------------- --------------------------------------------
0 71 264
I would like to take the above query and rotate the output to look more vertical.
ColName Value
--------------------------------------------- ---------
AccountingCode 0
ActiveCostAllocationCode1Segment1 71
ActiveCostAllocationCode1Segment1Description 264
I was trying to use PIVOT / UNPIVOT but could not figure how to make it work for this case.
Any ideas?

If you are working with SQL Sever then you can use APPLY :
SELECT tt.ColName, tt.val
FROM table t CROSS APPLY
( VALUES ('AccountingCode', AccountingCode),
('ActiveCostAllocationCode1Segment1', ActiveCostAllocationCode1Segment1),
('ActiveCostAllocationCode1Segment1Description', ActiveCostAllocationCode1Segment1Description)
) tt(ColName, Val);
In standard you can use UNION ALL to UNPIVOT the data.

The generic way in SQL is UNION ALL:
select 'AccountingCode', AccountingCode from t
union all
select 'ActiveCostAllocationCode1Segment1', ActiveCostAllocationCode1Segment1 from t
union all
select 'ActiveCostAllocationCode1Segment1Description', ActiveCostAllocationCode1Segment1Description
This assumes that the types of the columns are compatible (they all look like integers, so that is probably okay).
The better method is to use a lateral join (or apply in some databases), if your database supports it.

Related

How can I use a row value to dynamically select a column name in Oracle SQL 11g?

I have two tables, one with a single row for each "batch_number" and another with defect details for each batch. The first table has a "defect_of_interest" column which I would like to link to one of the columns in the second table. I am trying to write a query that would then pick the maximum value in that dynamically linked column for any "unit_number" in the "batch_number".
Here is the SQLFiddle with example data for each table: http://sqlfiddle.com/#!9/a1c27d
For example, the maximum value in the DEFECT_DETAILS.SCRATCHES column for BATCH_NUMBER = A1 is 12.
Here is my desired output:
BATCH_NUMBER DEFECT_OF_INTEREST MAXIMUM_DEFECT_COUNT
------------ ------------------ --------------------
A1 SCRATCHES 12
B3 BUMPS 4
C2 STAINS 9
I have tried using the PIVOT function, but I can't get it to work. Not sure if it works in cases like this. Any help would be much appreciated.
If the number of columns is fixed (it seems to be) you can use CASE to select the specific value according to the related table. Then aggregating is simple.
For example:
select
batch_number,
max(defect_of_interest) as defect_of_interest,
max(defect_count) as maximum_defect_count
from (
select
d.batch_number,
b.defect_of_interest,
case when b.defect_of_interest = 'SCRATCHES' then d.scratches
when b.defect_of_interest = 'BUMPS' then d.bumps
when b.defect_of_interest = 'STAINS' then d.stains
end as defect_count
from defect_details d
join batches b on b.batch_number = d.batch_number
) x
group by batch_number
order by batch_number;
See Oracle example in db<>fiddle.

How to calculate dynamically a column containing a formula in SQL Server a return the value

I've been searching for this but I dont know how to ask for this specific information.
Lets imagine I have something like this in my sql table.
Columns:
width : 10
height: 15
Depth: 6
And I have a formula column like this
formula: (W*2)+H+D+3
where I replace W with Width, H with Height, and D with depth.
using sql Replace, I am able to do this and convert the final result as
(10*2)+15+6+3
The problem is that I need the calculation to be done in the column as a result.
I tried this direcly in SQL
select 1 as width ,
2 as height ,
3 as depth ,
'H*2+W' as formula,
replace(Replace(REPLACE('H*2+W','W',1),'H',2),'D',3) as result
I need to be able to do this directly in the query, and calculate each row result with its specific value.
I tried doing Execs inside Select, but no luck. this would run 1000 querys if my initial query has 1000 rows...
How can I make this the best possible way?
You can't easily do what you want. SQL Server does not have a convenient parsing mechanism for creating code from strings. You could use dynamic SQL and a cursor, but that is cumbersome.
However, you may be able to store your formulas using coefficents:
formula w_coeff h_coeff d_coeff constant
(W*2)+H+D+3 2 1 1 3
'H*2+W' 1 2 0 0
Then you can do:
select v.*, f.*,
(f.w_coeff * v.w + f.h_coeff * v.h + f.d_coeff * v.d + f.constant)
from (values (1, 2, 3)) v(w, h, d) cross join
formulas f;

SQL Server - Finding Number patterns

I've been looking at this this for the last hour and just can't seem to find a way to do it, I'm sure its pretty simple but my google and reading skills have failed me.
All I need to do is to find ascending and descending numerical patterns in a field.
Like in this pseudo-SQL Code:
select * where col = '123456' or '23456' or '7654' or '987654321'
Most of the pattern methods using LIKE seem to be around placement of characters/numbers rather than the specific ordering,
I've started trying to create a query than takes the first character and compares it to the next one but this seems really ineffective and inefficient as it would need to take each field in the column run the query and return it if it matches.
I've managed to find a way to get it if its a repeated character but not if its an increase or decrease.
Any help would be greatly appreciated.
You can put regular expression inside your LIKE quotes.
Ascending:
^(?=\d{4,10}$)1?2?3?4?5?6?7?8?9?0?$
Descending:
^(?=\d{4,10}$)9?8?7?6?5?4?3?2?1?0?$
d{4,10} here is possible value length, between 4 and 10 symbols.
Won't be fast, most likely.
You can check how it works on http://rubular.com/.
Edit: Sorry, I forgot to mention you will have to do a MS SQL Server CLR integration first. By default, MSSQL Server does not fully support RegEx.
This article describes how to create and use extensions for the LIKE (Transact-SQL) clause that supports Regular Expressions.
http://www.codeproject.com/Articles/42764/Regular-Expressions-in-MS-SQL-Server
Another option could be something like this:
Declare #Table table (col int)
Insert into #Table values
(4141243),(4290577),(98765432),(78635389),(4141243),(22222),(4290046),(55555555),(4141243),(6789),(77777),(45678),(4294461),(55555),(4141243),(5555)
Declare #Num table (Num int);Insert Into #Num values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)
Select Distinct A.*
From #Table A
Join (
Select Patt=replicate(Num,3) from #Num
Union All
Select Patt=right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3) from #Num where Num<8
Union All
Select Patt=reverse(right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3)) from #Num where Num<8
) B on CharIndex(Patt,cast(col as varchar(25)))>0
Returns
Col
5555
6789
22222
45678
55555
77777
55555555
98765432
**
Think RUMMY 500. A groups or runs of 3. For example 123 or 321 or
333 would be a hit.
**

How to multiply a row?

I have a Postgres 9.0 query returning results in a way similar to this:
item;qty
AAAA;2
EEEE;3
What I would like is to transform that into:
AAAA
AAAA
EEEE
EEEE
EEEE
Is there any way I can do that on simple, i.e., without stored procedures, functions, etc?
There's a function 'generate_series' which can be used to generate a table of values. These can be used to repeat a column via joining:
select item
from data,generate_series(0,1000)
where generate_series<qty order by item;
Consider the following demo:
CREATE TEMP TABLE x(item text, qty int);
INSERT INTO x VALUES
('AAAA',2)
,('EEEE',3)
,('IIII',4);
SELECT regexp_split_to_table(rtrim(repeat(item||'~#~',qty),'~#~'),'~#~') AS item
FROM x;
Produces exactly the requested result.
In my tests it performs faster by an order of magnitude than the solution with generate_series().
Additional bonus: works with any number of qty.
Weakness: you need a delimiter-string not contained in any item.
SELECT
myTable.item
FROM
myTable
INNER JOIN
(SELECT 1 AS counter UNION ALL SELECT 2 UNION ALL SELECT 3) AS multiplier
ON multiplier.counter <= myTable.qty
Increase the number of UNIONS based on your Maximum value in qty
But I'd also follow #djacobson's advice : explain why you want to do this, as the may be a completely different approach altogether. Doing this feels, ummm, odd...

How to get a value from previous result row of a SELECT statement?

If we have a table called FollowUp and has rows [ ID(int) , Value(Money) ]
and we have some rows in it, for example
ID --Value
1------70
2------100
3------150
8------200
20-----250
45-----280
and we want to make one SQL Query that get each row ID,Value and the previous Row Value in which data appear as follow
ID --- Value ---Prev_Value
1 ----- 70 ---------- 0
2 ----- 100 -------- 70
3 ----- 150 -------- 100
8 ----- 200 -------- 150
20 ---- 250 -------- 200
45 ---- 280 -------- 250
i make the following query but i think it's so bad in performance in huge amount of data
SELECT FollowUp.ID, FollowUp.Value,
(
SELECT F1.Value
FROM FollowUp as F1 where
F1.ID =
(
SELECT Max(F2.ID)
FROM FollowUp as F2 where F2.ID < FollowUp.ID
)
) AS Prev_Value
FROM FollowUp
So can anyone help me to get the best solution for such a problem ?
This sql should perform better then the one you have above, although these type of queries tend to be a little performance intensive... so anything you can put in them to limit the size of the dataset you are looking at will help tremendously. For example if you are looking at a specific date range, put that in.
SELECT followup.value,
( SELECT TOP 1 f1.VALUE
FROM followup as f1
WHERE f1.id<followup.id
ORDER BY f1.id DESC
) AS Prev_Value
FROM followup
HTH
You can use the OVER statement to generate nicely increasing row numbers.
select
rownr = row_number() over (order by id)
, value
from your_table
With the numbers, you can easily look up the previous row:
with numbered_rows
as (
select
rownr = row_number() over (order by id)
, value
from your_table
)
select
cur.value
, IsNull(prev.value,0)
from numbered_rows cur
left join numbered_rows prev on cur.rownr = prev.rownr + 1
Hope this is useful.
This is not an answer to your actual question.
Instead, I feel that you are approaching the problem from a wrong direction:
In properly normalized relational databases the tuples ("rows") of each table should contain references to other db items instead of the actual values. Maintaining these relations between tuples belongs to the data insertion part of the codebase.
That is, if containing the value of a tuple with closest, smaller id number really belongs into your data model.
If the requirement to know the previous value comes from the view part of the application - that is, a single view into the data that needs to format it in certain way - you should pull the contents out, sorted by id, and handle the requirement in view specific code.
In your case, I would assume that knowing the previous tuples' value really would belong in the view code instead of the database.
EDIT: You did mention that you store them separately and just want to make a query for it. Even still, application code would probably be the more logical place to do this combining.
What about pulling the lines into your application and computing the previous value there?
Create a stored procedure and use a cursor to iterate and produce rows.
You could use the function 'LAG'.
SELECT ID,
Value,
LAG(value) OVER(ORDER BY ID) AS Prev_Value
FROM FOLLOWUP;