SQL Select different column values into one row - sql

I have a table with values something like this:
StoreID | ItemID | OpeningClosingBalance | Total
1 | 1 | O | 10
1 | 1 | C | 20
1 | 2 | O | 5
1 | 2 | C | 7
To the first row is an opening balance of 10 for a specific item. The second row is the closing balance of 20 for that same item. Row 3 is opening for another item, and then is closing balance ect. I would like a query with results displayed as follows:
StoreID | ItemID | Openingbalance | ClosingBalance
1 | 1 | 10 | 20
1 | 2 | 5 | 7
Can anyone please assist?

You can do this with conditional aggregation:
select StoreId, ItemId,
max(case when OpeningClosingBalance = 'O' then total end) as openingbalance,
max(case when OpeningClosingBalance = 'C' then total end) as closingbalance
from t
group by StoreId, ItemId;

Related

return true if the column which have the same ProductID

i have table name stock in which i have 5 column name id productId stockIn stockOut And VoucherType ..
i want to check the if productId=1 and voucherType=1 that count all the column in stockIn with the same ProductId and Sum All the value in stockIn then also count in stockout with same product id and sum if the stockIn sum is greater then stockOut that return true...
id ' productid ' stockin 'stockout 'VoucherType
-----------------------------------------
1 | 1 | 5 | 0 | 1
2 | 1 | 5 | 0 | 1
3 | 1 | 5 | 0 | 1
4 | 2 | 5 | 0 | 1
5 | 2 | 0 | 10 | 2
6 | 1 | 0 | 2 | 2
7 | 2 | 0 | 3 | 2
SELECT productId
, voucherType
, COUNT(stockIn) as Count_stockIn
, SUM(stockIn) as Sum_stockIn
, COUNT(stockOut) as Count_stockOut
, CASE WHEN SUM(stockIn) > SUM(stockOut) THEN 'True' ELSE 'False' END AS IsInGreater
From Table
Group By productId, voucherType
Having productId = voucherType And IsInGreater = 'True'
This is kind of what you want? (your question is seriously unclear)

Update a column and refer back it in the same query

I have a table in SQL Server 2014 and need to recursively update a column based on its previous value. For e.g.
---------------------------------------
ID | price | diff_with_prev_price |
---------------------------------------
1 | 29 | 0 |
2 | 25 | 0 |
3 | 20 | 0 |
4 | 35 | 0 |
5 | 40 | 0 |
--------------------------------------|
I want to recursively update third column like below
---------------------------------------
ID | price | diff_with_prev_price |
---------------------------------------
1 | 29 | 0 |
2 | 25 | 25 |
3 | 20 | 5 |
4 | 35 | -30 |
5 | 40 | 10 |
--------------------------------------|
It is the summation of previous value of third column with next value of 'price'.
Can someone please give some hint to do this either using CTE or LEAD/LAG, but without using cursors. I have to update million rows.
You can try this:
SELECT 1 AS ID , 29 AS price, 0 AS diff_with_prev_prive
INTO #tmp
UNION SELECT 2 AS ID , 25 AS price, 0 AS diff_with_prev_prive
UNION SELECT 3 AS ID , 20 AS price, 0 AS diff_with_prev_prive
UNION SELECT 4 AS ID , 35 AS price, 0 AS diff_with_prev_prive
UNION SELECT 5 AS ID , 40 AS price, 0 AS diff_with_prev_prive
WITH cte AS
(
SELECT
ID
, price
, diff_with_prev_prive
, price - ISNULL(LAG(price) OVER (ORDER BY ID),0) AS new_value
FROM #tmp
)
UPDATE t
SET diff_with_prev_prive = t.new_value
FROM cte t
SELECT * FROM #tmp

Return all records if more than 2/3 satisfy a value

I have a table representing multiple transactions by customers in any given day. I need to return all transactions per customer if two thirds or more of the transactions per customer were cash instead of credit card.
In the example below I want to return all of customers' 1, 4 transactions as they were the only customers to have 2 thirds or more of their transactions as cash:
+----------------+-------------+-----------------+------------------+
| Transaction ID | CustomerNum | TransactionType | TransactionValue |
+----------------+-------------+-----------------+------------------+
| 1 | 1 | Cash | 11 |
| 2 | 1 | Card | 12 |
| 3 | 1 | Cash | 13 |
| 4 | 2 | Cash | 14 |
| 5 | 2 | Card | 15 |
| 6 | 3 | Cash | 15 |
| 7 | 3 | Card | 11 |
| 8 | 3 | Cash | 12 |
| 9 | 3 | Card | 13 |
| 10 | 4 | Cash | 14 |
| 11 | 4 | Cash | 15 |
| 12 | 4 | Cash | 15 |
+----------------+-------------+-----------------+------------------+
This seems to work with the sample data:
declare #t table (TranID int not null,CustomerNum int not null,
TranType varchar(17) not null,TranValue decimal(18,0) not null)
insert into #t(TranID,CustomerNum,TranType,TranValue) values
( 1,1,'Cash',11), ( 2,1,'Card',12), ( 3,1,'Cash',13),
( 4,2,'Cash',14), ( 5,2,'Card',15),
( 6,3,'Cash',15), ( 7,3,'Card',11), ( 8,3,'Cash',12), ( 9,3,'Card',13),
(10,4,'Cash',14), (11,4,'Cash',15), (12,4,'Cash',15)
;With Counted as (
select *,
COUNT(*) OVER (PARTITION BY CustomerNum) as cnt,
SUM(CASE WHEN TranType='Cash' THEN 1 ELSE 0 END)
OVER (PARTITION BY CustomerNum) as cashcnt
from #t
)
select * from Counted
where cashcnt * 3 >= cnt * 2
I've gone with simple multiplication at the end to keep all of the maths as integers and avoid having to think about float/decimal and the representation of 2/3.
Result:
TranID CustomerNum TranType TranValue cnt cashcnt
----------- ----------- ----------------- ----------- ----------- -----------
1 1 Cash 11 3 2
2 1 Card 12 3 2
3 1 Cash 13 3 2
10 4 Cash 14 3 3
11 4 Cash 15 3 3
12 4 Cash 15 3 3
Try this:
select t.*
from (select customernum
from transactions
group by customernum
having sum(case when TransactionType = 'Cash' then 1.0 else 0.0 end) / sum(1.0) > 0.6666) c
join transactions t on t.customernum = c.customernum

Select dynamic couples of lines in SQL (PostgreSQL)

My objective is to make dynamic group of lines (of product by TYPE & COLOR in fact)
I don't know if it's possible just with one select query.
But : I want to create group of lines (A PRODUCT is a TYPE and a COLOR) as per the number_per_group column and I want to do this grouping depending on the date order (Order By DATE)
A single product with a NB_PER_GROUP number 2 is exclude from the final result.
Table :
-----------------------------------------------
NUM | TYPE | COLOR | NB_PER_GROUP | DATE
-----------------------------------------------
0 | 1 | 1 | 2 | ...
1 | 1 | 1 | 2 |
2 | 1 | 2 | 2 |
3 | 1 | 2 | 2 |
4 | 1 | 1 | 2 |
5 | 1 | 1 | 2 |
6 | 4 | 1 | 3 |
7 | 1 | 1 | 2 |
8 | 4 | 1 | 3 |
9 | 4 | 1 | 3 |
10 | 5 | 1 | 2 |
Results :
------------------------
GROUP_NUMBER | NUM |
------------------------
0 | 0 |
0 | 1 |
~~~~~~~~~~~~~~~~~~~~~~~~
1 | 2 |
1 | 3 |
~~~~~~~~~~~~~~~~~~~~~~~~
2 | 4 |
2 | 5 |
~~~~~~~~~~~~~~~~~~~~~~~~
3 | 6 |
3 | 8 |
3 | 9 |
If you have another way to solve this problem, I will accept it.
What about something like this?
select max(gn.group_number) group_number, ip.num
from products ip
join (
select date, type, color, row_number() over (order by date) - 1 group_number
from (
select op.num, op.type, op.color, op.nb_per_group, op.date, (row_number() over (partition by op.type, op.color order by op.date) - 1) % nb_per_group group_order
from products op
) sq
where sq.group_order = 0
) gn
on ip.type = gn.type
and ip.color = gn.color
and ip.date >= gn.date
group by ip.num
order by group_number, ip.num
This may only work if your nb_per_group values are the same for each combination of type and color. It may also require unique dates, but that could probably be worked around if required.
The innermost subquery partitions the rows by type and color, orders them by date, then calculates the row numbers modulo nb_per_group; this forms a 0-based count for the group that resets to 0 each time nb_per_group is exceeded.
The next-level subquery finds all of the 0 values we mapped in the lower subquery and assigns group numbers to them.
Finally, the outermost query ties each row in the products table to a group number, calculated as the highest group number that split off before this product's date.

Get MIN MAX grouping by closer distance

shops
id_shop | id_prod_ty | position
and
products
id | price | id_prod_ty | distance
table shops contains 2 shops for each id_prod_ty (product type) and a position.
table products contains many records with different prices and a distance
basically i need to have a query that selects price low and high for each product and for each shops grouping by closer prices (and that are not closer to other shops)
so for example
shops
id_shop | id_prod_ty | position
1 | 1 | 3
2 | 1 | 7
3 | 2 | 8
4 | 2 | 4
....
products
id | price | id_prod_ty | distance
1 | 10 | 1 | 1
2 | 04 | 1 | 2
3 | 02 | 1 | 4
4 | 44 | 1 | 2
5 | 09 | 1 | 1
6 | 13 | 1 | 7
7 | 15 | 1 | 8
8 | 09 | 2 | 5
9 | 12 | 2 | 8
10 | 17 | 2 | 1
11 | 32 | 2 | 13
12 | 22 | 2 | 2
...
result shout be like this
id_prod_ty | id_price_low | id_price_high | id_shop
1 | 3 (02) | 4 (44) | 1
1 | 6 (13) | 7 (15) | 2
2 | 8 (09) | 12 (22) | 4
2 | 9 (12) | 11 (32) | 3
...
thanks
I think I understand the problem. For each price, you are trying to assign the shop that is nearest, based on the distance and the position.
The approach starts by joining the positions and shops. It then calculates the difference between the position and distance -- that seems to be the measure you are using. Each price id will appear twice (once for each shop). Using a window function, it calculates the minimum difference for each id.
With this information, the query can determine which is the closer shop. This version returns the prices, rather than the ids of the lowest prices. Here is the final, untested, query:
select id_prod_ty,
MIN(case when diff = minDiff then price) as price_low,
MAX(case when diff = minDiff then price) as price_high,
s.id_shop
from (select p.id_prod_ty,
s.id_shop,
p.price,
(p.distance - s.position) as diff,
MIN(p.distance - s.position) over (partition by p.id) as minDiff
from products p join
shops s
on p.id_prod_ty = s.id_prod_ty
) ps
group by id_prod_ty, id_shop
Here is a variation that gets the ids as well. It uses a window function to find the min and max price, and then compares the price to these values to get the ids:
select id_prod_ty,
MIN(minPrice) as price_low,
MIN(case when price = minPrice then id end) id_price_low,
MAX(maxprice) as price_high,
MIN(case when price = maxPrice then id end) id_price_high,
id_shop
from (select *,
MIN(IsThisShopPrice) over (partition by id_prod_ty, id_shop) as minPrice,
MIN(IsThisShopPrice) over (partition by id_prod_ty, id_shop) as maxPrice,
from (select p.id_prod_ty, s.id_shop, p.price, p.id,
(p.distance - s.position) as diff,
(case when (p.distance - s.position) = MIN(p.distance - s.position) over (partition by p.id)
then 'Y'
else 'N'
end) as IsThisShop
(case when (p.distance - s.position) = MIN(p.distance - s.position) over (partition by p.id)
then price
end) as IsThisShopPrice
from products p join
shops s
on p.id_prod_ty = s.id_prod_ty
) ps
) ps
group by id_prod_ty, id_shop