Insert data into temp table, multiple columns from one Table - sql

I have a table with columns: ID (Int), Date (Date) and Price (Decimal). Date column is in format 2013-04-14:
Table Example
ID Date Price
1 2012/05/02 23.5
1 2012/05/03 25.2
1 2012/05/04 22.5
1 2012/05/05 22.2
1 2012/05/06 26.5
2 2012/05/02 143.5
2 2012/05/03 145.2
2 2012/05/04 142.2
2 2012/05/05 146.5
3 2012/05/02 83.5
3 2012/05/03 85.2
3 2012/05/04 80.5
Query Example:
I want to be able to select all ID1 and ID3's data between a date range from the table and have this in a table with three columns, ordered by Date column. Also I would want to insert this into a temporary table to perform mathematical calculations on the data. Please comment if there is a better way.
Correct Result Example
Date ID1 ID3
2012-05-02 23.5 83.5
2012-05-03 25.2 85.2
2012-05-04 22.5 80.2
Any help and advice will be appreciated,
Thanks

Try the following.
CREATE TABLE #temp (
Date date,
x money,
y money
)
;
SELECT
Date,
MAX(CASE WHEN id=1 THEN price END) AS x,
MAX(CASE WHEN id=3 THEN price END) AS y
FROM Top40
WHERE Date BETWEEN '2012-05-02' AND '2012-05-04'
GROUP BY
Date
;
See SQL Fiddle for working example
EDIT:
To use the LAG window function on the x and y columns, you'll have to use a common table expression or CTE first.
WITH prices AS(
SELECT
Date as myDate,
MAX(CASE WHEN id=1 THEN price END) AS x,
MAX(CASE WHEN id=3 THEN price END) AS y
FROM Top40
WHERE Date BETWEEN '2012-05-02' AND '2012-05-04'
GROUP BY
Date
)
SELECT
myDate,
p.x,
(p.x/(LAG(p.x) OVER (ORDER BY MyDate))-1) as x_return,
p.y,
(p.y/(LAG(p.y) OVER (ORDER BY MyDate))-1) as y_return
FROM prices p
ORDER BY
myDate
;
See new SQL Fiddle for example.

The simplest way to do it in code (although it may not perform well with large data sets) is to do something like:
SELECT [Date], x = MAX(CASE WHEN ID = 1 THEN PRICE END)
, y = MAX(CASE WHEN ID = 3 THEN PRICE END)
INTO #tmp
FROM Top40
GROUP BY [Date]

Or...
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
As far as populating a temp table, any of the usual ways works:
Table variable:
declare #work table
(
yyyymmdd varchar(32) not null ,
stock_1_price money null ,
stock_3_price money null
)
insert #work ( yyyymmdd , stock_1_price , stock_3_price )
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
Declared temp table in tempdb
create table #work
(
yyyymmdd varchar(32) not null primary key clustered ,
stock_1_price money null ,
stock_3_price money null
)
insert #work ( yyyymmdd , stock_1_price , stock_3_price )
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
non-declare temp table in tempdb via select into:
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
into #work
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date

Related

SQL - find row with closest date but different column value

i'm new to SQL and i would need an help.
I have a TAB and I need to find for any item B in the TAB the item A with the closest date. In this case the A with 02.09.2021 04:25:30
Date.
Item
07.09.2021 05:02:05
A
06.09.2021 05:01:02
A
05.09.2021 05:00:02
A
04.09.2021 04:59:01
A
03.09.2021 04:58:03
A
02.09.2021 04:56:55
A
02.09.2021 04:33:56
B
02.09.2021 04:25:30
A
WITH CTE(DATE,ITEM)AS
(
SELECT '20210907 05:02:05' , 'A'UNION ALL
SELECT '20210906 05:01:02' , 'A'UNION ALL
SELECT '20210905 05:00:02' , 'A'UNION ALL
SELECT'20210904 04:59:01' , 'A'UNION ALL
SELECT'20210903 04:58:03' , 'A'UNION ALL
SELECT'20210902 04:56:55' , 'A'UNION ALL
SELECT'20210902 04:33:56' , 'B'UNION ALL
SELECT'20210902 04:25:30' , 'A'
)
SELECT
CAST(C.DATE AS DATETIME)X_DATE,C.ITEM,Q.CLOSEST
FROM CTE AS C
OUTER APPLY
(
SELECT TOP 1 CAST(X.DATE AS DATETIME)CLOSEST
FROM CTE AS X
WHERE X.ITEM='A'AND CAST(X.DATE AS DATETIME)<CAST(C.DATE AS DATETIME)
ORDER BY CAST(X.DATE AS DATETIME) ASC
)Q
WHERE C.ITEM='B'
You can use OUTER APPLY-approach as in the above query.
Please also take a look that datetime-column (DATE)is written in the ISO-compliant form
Your data has only two columns. If you want the only the closest A timestamp, then the fastest way is probably window functions:
select t.*,
(case when prev_a_date is null then next_a_date
when next_a_date is null then prev_a_date
when datediff(second, prev_a_date, date) <= datediff(second, date, next_a_date) then prev_a_date
else next_a_date
end) as a_date
from (select t.*,
max(case when item = 'A' then date end) over (order by date) as prev_a_date,
min(case when item = 'A' then date end) over (order by date desc) as next_a_date
from t
) t
where item = 'B';
This uses seconds to measure the time difference, but you can use a smaller unit if appropriate.
You can also do this using apply if you have more columns from the "A" rows that you want:
select tb.*, ta.*
from t b outer apply
(select top (1) ta.*
from t ta
where item = 'A'
order by abs(datediff(second, a.date, b.date))
) t
where item = 'B';

SQL: Optimize query with multiple CASE statements

I have a query with many CASE statements that runs for a very long time due to the number of rows. In my research I have not found a solution yet. Is there a way to write the CASE statements more efficiently and with better performance?
database: Oracle
table_a
table
table_y
are all the same table where I SELECT from.
example data
contract_number
product_description
product
damagenumber
date
internalname
payment
1
Product T-Shirt
product_name
111
20210101
Web
30.20
2
Product T-Shirt
product_name
222
20210202
Web
19.38
3
Product Hoodie
product_name2
333
20210215
Store
20.49
3
Product Hoodie
product_name2
334
20210302
Store
15.99
5
Product Hoodie
product_name2
123
20210120
Telephone
99.99
SELECT
contract_number,
product_description,
product,
CASE
WHEN ( x.produkt = 'product_name'
AND (
SELECT
COUNT(DISTINCT damagenumber)
FROM
table z
WHERE
date BETWEEN add_months(trunc(sysdate), - 6) AND sysdate
AND internalname <> 'CONDITION'
AND x.contract_number = z.contract_number
GROUP BY
z.contract_number
) = 1
AND (
SELECT
SUM(y.payment)
FROM
table_y y
WHERE
date BETWEEN add_months(trunc(sysdate), - 6) AND sysdate
AND internalname <> 'CONDITION'
AND x.contract_number = y.contract_number
) > 1500 ) THEN
(
SELECT
COUNT(DISTINCT damagenumber)
FROM
table z
WHERE
date BETWEEN add_months(trunc(sysdate), - 6) AND sysdate
AND internalname <> 'CONDITION'
AND x.contract_number = z.contract_number
GROUP BY
z.contract_number
)
ELSE
0
END) AS count_numbers,
FROM
table_a x
GROUP BY
x.contract_number,
x.product_description,
x.product;
The above is a simplified example. I have a lot of WHEN conditions in my query.
Thanks in advance
maybe this help
with tabletemp as (
SELECT z.contract_number
, COUNT(DISTINCT damagenumber) damagenumber_count
FROM table z
WHERE date BETWEEN add_months(trunc(sysdate), - 6) AND sysdate AND internalname <> 'CONDITION'
GROUP BY z.contract_number
), tabletemp2 as (
SELECT y.contract_number
, SUM(y.payment) payment_sum
FROM table_y y
WHERE date BETWEEN add_months(trunc(sysdate), - 6) AND sysdate AND internalname <> 'CONDITION'
group by y.contract_number
)
SELECT
contract_number,
product_description,
product,
CASE WHEN ( x.produkt = 'product_name' AND tt.damagenumber_count = 1 AND tt2.payment_sum > 1500 ) THEN
tt.damagenumber_count
ELSE
0
END AS count_numbers,
FROM
table_a x
join tabletemp tt on (tt.contract_number = x.contract_number)
join tabletemp2 tt2 on (tt2.contract_number = x.contract_number)
Maybe this query have some errors (I can't test) but you should try this way

Splitting value to two columns in SQL

I have a table that stores the VIN numbers and delivery dates of vehicles based on a code. I want to be able to get one row with three columns of data.
I have tried the following
SELECT DISTINCT VIN, MAX(TRANSACTION_DATE) AS DELIVERY_DATE
FROM "TABLE"
WHERE DELIVERY_TYPE ='025'
AND VIN IN ('XYZ')
GROUP BY VIN
UNION ALL
SELECT VIN, MAX(TRANSACTION_DATE) AS OTHER_DELIVERY_DATE
FROM "TABLE"
WHERE DELIVERY_TYPE !='025'
AND VIN IN ('XYZ')
GROUP BY VIN;
When I run this I get
VIN DELIVERY_DATE
XYZ 26-dec-18
XYZ 01-MAY-19
current data format in table:
VIN TRANSACTION_DATE
XYZ 26-DEC-18
XYZ 01-MAY-19
Required format:
VIN DELIVERY_DATE OTHER_DELIVERY DATE
XYZ 26-DEC-18 01-MAY-19
use conditional aggregation
SELECT VIN,
MAX (CASE WHEN DELIVERY_TYPE ='025' AND
VIN IN ('XYZ') then TRANSACTION_DATE end) AS DELIVERY_DATE
MAX(CASE WHEN DELIVERY_TYPE !='025' AND
VIN IN ('XYZ') then TRANSACTION_DATE end) AS OTHER_DELIVERY
FROM "TABLE"
GROUP BY VIN
Just use conditional aggregation:
SELECT VIN,
MAX(CASE WHEN DELIVERY_TYPE = 25 THEN TRANSACTION_DATE END) AS DELIVERY_DATE,
MAX(CASE WHEN DELIVERY_TYPE <> 25 THEN TRANSACTION_DATE END) AS TRANSACTION_DATE
FROM TABLE
WHERE VIN IN ('XYZ')
GROUP BY VIN;
Note that SELECT DISTINCT is almost never used with GROUP BY.
You can use CROSS APPLY
DECLARE #Cars TABLE (VIN VARCHAR(100), DELIVERY_TYPE VARCHAR(3), TRANSACTION_DATE DATE)
INSERT INTO #Cars
(VIN, DELIVERY_TYPE , TRANSACTION_DATE)
VALUES
('XYZ', '025', '20181226'), ('XYZ', '030', '20190319')
I needed above code to be able to run without a table and data, all you need is this:
SELECT DISTINCT C.VIN, DD.DELIVERY_DATE, TD.TRANSACTION_DATE
FROM #Cars C
CROSS APPLY (SELECT MAX(TRANSACTION_DATE) DELIVERY_DATE FROM #Cars D WHERE D.DELIVERY_TYPE = '025' AND D.VIN = C.VIN) DD
CROSS APPLY (SELECT MAX(TRANSACTION_DATE) TRANSACTION_DATE FROM #Cars D WHERE D.DELIVERY_TYPE = '025' AND D.VIN = C.VIN) TD
If you need to transpond not two but a lot more columns, I'd suggest using PIVOT TABLE as more appropriate, but for two columns either CROSS APPLY or conditional aggregation will do the trick.

Display two count from a single in two different column from a single table

I have a table where I record daily work of employees. I have a query where I display the current work for today for each employee and have another query where I display the total count of work for each employee.
I want to combine the 2 queries into a single one where I have a daily column and a cumulative column.
my query is below:
SELECT staff,
process_inprogress,
not_yet_completed
FROM (SELECT staff,
Count(number) AS Process_InProgress,
Count(team_name) AS Not_Yet_Completed
FROM dbo.empty_shell_workflow
WHERE ( end_date IS NULL )
AND ( process_name IS NOT NULL )
AND ( billing_amount IS NULL )
AND ( deletion IS NULL )
AND ( team_name = 'Team Vishma' )
AND ( CONVERT(DATE, start_date) = CONVERT(DATE, Getdate()) )
GROUP BY staff
UNION ALL
SELECT staff,
Count(number) AS Process_InProgress,
Count(team_name) AS Not_Yet_Completed
FROM dbo.empty_shell_workflow AS Empty_Shell_Workflow_1
WHERE ( team_name = 'Team Vishma' )
AND ( billing_amount IS NULL )
AND ( tag_number IS NULL )
AND ( initiator IS NOT NULL )
AND ( end_date IS NULL )
AND ( deletion IS NULL )
AND ( process_name IS NOT NULL )
GROUP BY staff) AS t
however it is being display only in a single column for both daily and cumulative
Below is how i want it to display
Staff Process_Progress(Daily) Not_YetCompleted(Cumulative)
A 2 5
B 0 1
C 6 8
however from the query above, the cumulative is being display in the daily column
Any idea, how can I modify the query?
you could try like below by using case when
with cte as
( SELECT staff,CONVERT(DATE, start_date) as date_of_month
Count(number) AS Process_InProgress
FROM dbo.empty_shell_workflow AS Empty_Shell_Workflow_1
WHERE ( team_name = 'Team Vishma' )
AND ( billing_amount IS NULL )
AND ( tag_number IS NULL )
AND ( initiator IS NOT NULL )
AND ( end_date IS NULL )
AND ( deletion IS NULL )
AND ( process_name IS NOT NULL )
GROUP BY staff,CONVERT(DATE, start_date)
) select staff, sum(case when date_of_month = CONVERT(DATE, Getdate()) then
Process_InProgress else 0 end) as Process_Progress_Daily,
sum(case when date_of_month != CONVERT(DATE, Getdate()) then
Process_InProgress else 0 end) as Not_YetCompleted
from cte
group by staff

SQL Rollup last 4 weeks total

I have a table which I want to get the previous four weeks Order total in a query. But I want to return it with a SELECT (A total of the row's previous 4 weeks Order1 column - if they exist)
PurchasingID Order1 Date FourWeekTotal
------------ ------------------- ------- ---------------
1 1.00 2013-04-21 14.00
2 2.00 2013-04-14 12.00
3 3.00 2013-04-07 9.00
4 4.00 2013-03-31 5.00
5 5.00 2013-03-24 0.00
My understanding is for each record in your table, you want to see the sum of Order1 for itself and each record that has a Date value within four weeks prior to the primary record. Here you go:
create table MysteryTable
(
PurchasingId int not null primary key identity(1,1),
Order1 money not null,
[Date] date not null
)
insert MysteryTable( Order1, [Date] ) values ( 1.00, '2013-04-21' )
insert MysteryTable( Order1, [Date] ) values ( 2.00, '2013-04-14' )
insert MysteryTable( Order1, [Date] ) values ( 3.00, '2013-04-07' )
insert MysteryTable( Order1, [Date] ) values ( 4.00, '2013-03-31' )
insert MysteryTable( Order1, [Date] ) values ( 5.00, '2013-03-24' )
select
t1.PurchasingId
, t1.Order1
, t1.Date
, SUM( ISNULL( t2.Order1, 0 ) ) FourWeekTotal
from
MysteryTable t1
left outer join MysteryTable t2
on DATEADD( ww, -4, t1.Date ) <= t2.Date and t1.Date > t2.Date
group by
t1.PurchasingId
, t1.Order1
, t1.Date
order by
t1.Date desc
Explanation:
Join the table on itself, t1 representing the records to return, t2 to be the records to aggregate. Join based on t1's Date minus four weeks being less than or equal to t2's Date and t1's Date being greater than t2's Date. Then group the records by the t1 fields and sum t2.Order1. Left outer join is to account for the one record that will not have any preceding data.
Try this...
Declare #LBDate date
SET #LBDate = DATEADD(d,-28,getdate())
Now write ur select query...
Select * from Orders where Date between #LBDate and Getdate()
You can also use your required date instead to current date..