I have a table, TableA, that looks like this:
ColA ColB
0 20
1 10
0 5
1 15
I want to sort the rows so that all the records where ColA = 0 are listed first, and then these records are sorted by ColB ascendingly. After all the rows with ColA = 0 are listed, I then want to list all the rows with ColA = 1 but these rows sorted by ColB descendingly.
The results should look like this:
ColA ColB
0 5
0 20
1 15
1 10
Is this possible? Thanks for your help.
select t.ColA, t.ColB
from t
order by t.ColA
,case when t.ColA = 0 then t.ColB end asc
,case when t.ColA = 1 then t.ColB end desc
SELECT ColA,ColB
FROM table
ORDER BY
ColA, (CASE WHEN ColA = 1 THEN -1 * ColB ELSE ColB END)
Related
I want to update a table with the sum of a second table
This is the table 'x' that I want to update. Has a starting value and a closing value:
id
op_date
initial_value
end_value
1
2020-02-01
0
0
1
2020-02-02
0
0
2
2020-02-01
0
0
2
2020-02-02
0
0
The table 'y' save the values of the day:
id
op_date
value_day
1
2020-01-29
500
1
2020-02-01
100
1
2020-02-02
200
2
2020-01-29
750
2
2020-02-01
100
2
2020-02-02
250
I want the result to look like this:
id
op_date
initial_value
end_value
1
2020-02-01
500
600
1
2020-02-02
600
800
2
2020-02-01
750
850
2
2020-02-02
850
1100
I tried this script, but the process just runs it and doesn't finish it:
UPDATE x
SET
initial_value= (select sum(y.value_day)
from public.y where
y.op_date > '2020-11-01' and y.op_date < x.op_date
and y.id = x.id),
end_value= (select sum(y.value_day)
from public.y where
y.op_date between '2020-11-01' and x.op_date
and y.id = x.id);
You can use window function. To understand window function more you can look this link.
At first i am writing query to select the value.
select id,op_date,
sum(value_day) over (
partition by y.id
rows between unbounded preceding and current row
)-value_day as initial_value,
sum(value_day) over (
partition by y.id
rows between unbounded preceding and current row
) as end_value
from y
;
This is your update query.
UPDATE x
set initial_value=s_statement.initial_value,
end_value=s_statement.end_value
from
(select id,op_date,
sum(value_day) over (
partition by y.id
rows between unbounded preceding and current row
)-value_day as initial_value,
sum(value_day) over (
partition by y.id
rows between unbounded preceding and current row
) as end_value
from y) s_statement
where x.id=s_statement.id
and x.op_date=s_statement.op_date
;
Let me know if its ok with you.
Think of a table like below:
unique_id
a_column
b_column
a_int
b_int
date_created
Let's say data is like:
-unique_id -a_column -b_column -a_int -b_int -date_created
1z23 abc 444 0 1 27.12.2016 18:03:00
2c31 abc 444 0 0 26.12.2016 13:40:00
2e22 qwe 333 0 1 28.12.2016 15:45:00
1b11 qwe 333 1 1 27.12.2016 19:00:00
3a33 rte 333 0 1 15.11.2016 11:00:00
4d44 rte 333 0 1 27.09.2016 18:00:00
6e66 irt 333 0 1 22.12.2016 13:00:00
7q77 aaa 555 1 0 27.12.2016 18:00:00
I want to get the unique_id s where b_int is 1, b_column is 333 and considering a_column, a_int column must always be 0, if there are any records with a_int = 1 even if there are records with a_int = 0 these records must not be shown in the result. Desired result is: " 3a33 , 6e66 " when grouped by a_column and ordered by date_created and got top1 for each unique a_column.
I tried lots of "with ties" and "over(partition by" samples, searched questions, but couldn't manage to do it. This is what I could do:
select unique_id
from the_table
where b_column = '333'
and b_int = 1
and a_column in (select a_column
from the_table
where b_column = '333'
and b_int = 1
group by a_column
having sum(a_int) = 0)
order by date_created desc;
This query returns the result like this " 3a33 ,4d44, 6e66 ". But I don't want "4d44".
You were on the right track with the partitions and window functions. This solution uses ROW_NUMBER to assign a value to the a_column so we can see where there is more than 1. The 1 is the most recent date_created. Then you select from the result set where the row_counter is 1.
;WITH CTE
AS (
SELECT unique_id
, a_column
, ROW_NUMBER() OVER (
PARTITION BY a_column ORDER BY date_created DESC
) AS row_counter --This assigns a 1 to the most recent date_created and partitions by a_column
FROM #test
WHERE a_column IN (
SELECT a_column
FROM #test
WHERE b_column = '333'
AND b_int = 1
GROUP BY a_column
HAVING MAX(a_int) < 1
)
)
SELECT unique_ID
FROM cte
WHERE row_counter = 1
I have the following situation
ID Value
1 50
1 60
2 70
2 80
1 0
2 50
I need to run a query that would return summed value, grouped by ID. The catch is if the value is 0, then the entire sum should be 0.
Query results would be
ID Value
1 0
2 200
I tried
select ID, case
when Value> 0 then sum(Value) * 1
when Value= 0 then sum(value) * 0
end
from table
but that did not work.
select ID,
sum(value)*sign(min(abs(value))) as [sum(value)]
from YourTable
group by ID
With a case if you like:
select ID,
case sign(min(abs(value)))
when 0 then 0
else sum(value)
end as [sum(value)]
from YourTable
group by ID
This is an example of what I want to do:
I have a table called: TEST it has two columns: ColA and ColB
It has the following data:
ColA ColB
---- ----
0 1
0 1
0 3
2 1
2 3
I want to retrieve all values where ColA > 0, except I want to still include rows where ColA = 0 if ColB = 3
The following should work:
SELECT *
FROM TEST
WHERE ColA > 0 --All rows where ColA > 0
OR (ColA = 0 AND ColB = 3) -- All rows where ColA = 0 AND ColB = 3
Try This SQL
SELECT * FROM TEST WHERE ColA > 0 OR ( ColA = 0 AND ColB = 3)
It returns the following data
ColA ColB
0 3
2 1
2 3
Hope it helps.
SELECT * FROM TEST WHERE colA > 0 OR (colA=0 AND colB=3);
Not test yet, but hopefully this should work.
I have a customer table and an orderdetail table
the customer id is a foriegn key in the orderdetail table (I'm simplifying here)
The orderdetail table contains the following columns
OrderId
ItemId
CustomerId
Size
The Size column can take on any one of the following values
1. lr
2. md
3. sm
So the orderdetail table could have the following records (I've comma delimited the columns)
OrderId ItemId CustomerId Size
1,1,30,lr
1,1,30,md
1,1,30,sm
2,1,30,lr
2,1,30,md
3,1,30,lr
3,1,30,sm
4,1,30,lr
5,1,30,md
6,2,30,sm
7,3,30,md
8,3,30,lr
What I'd like is a really efficient query (there's millions of records in the order details tables) that has the following output for a given customerId (30 in this case)
ItemId SizeLr SizeMd SizeSm
1 4 3 2
2 0 0 1
3 1 1 0
The query I'm using uses 3 group by queries (one each for "lr", "md" and "sm") and as a result it scans the table 3 times.
I'm looking for a solution that scans the table just onces. I think the solution is using the new Grouping Set feature in MSSQL 2008. But either ways, a solution using one scan if what I hope someone can help me with.
EDIT
The actual output needs to have other fields from the customer table and the order details table as well. These other fields are not dependent on the aggregates.
For example
ItemName ItemId SizeLr SizeMd SizeSm
A 1 4 3 2
B 2 0 0 1
C 3 1 1 0
Totals 5 4 4
It would nice if I could get the totals for each of the Size columns as well
How about this:
SELECT ItemId,
SUM(CASE WHEN Size = 'Lr' THEN 1 ELSE 0 END) AS SizeLr,
SUM(CASE WHEN Size = 'Md' THEN 1 ELSE 0 END) AS SizeMd,
SUM(CASE WHEN Size = 'Sm' THEN 1 ELSE 0 END) AS SizeSm
FROM OrderDetail
WHERE CustomerId = 30
GROUP BY ItemId
Try this:
select Itemid,
sum (case when Size = 'lr' then 1 else 0 end) SizeLR,
sum (case when Size = 'Md' then 1 else 0 end) SizeMd,
sum (case when Size = 'SM' then 1 else 0 end) SizeSM
from orderdetail
group by Itemid
order by Itemid;
If ItemName is dependent from ItemId you can do this:
select Itemname, Itemid,
sum (case when Size = 'lr' then 1 else 0 end) SizeLR,
sum (case when Size = 'Md' then 1 else 0 end) SizeMd,
sum (case when Size = 'SM' then 1 else 0 end) SizeSM
from orderdetail
group by Itemid, Itemname
order by Itemid;