I have an sql script below.
SELECT
InvoiceNo
,InvoiceType
,Amount
,OrderAmount
,ShippingAmount
,TruckTaxAmount
,PreShippingAmount
FROM truckdb AS t1
INNER JOIN truckdetails AS t2 ON tl.truckdetail = t2.truckid
WHERE [shipping date] > = '01-01-2011'
And sample data
+--------+-------------+---------+-------------+----------------+------------+----------+
| InvNo | InvoiceType | Amount | OrderAmount | ShippingAmount | TruckTxAmt | PreShAmt |
+--------+-------------+---------+-------------+----------------+------------+----------+
| 001 | ckt | 1200 | 544 | 666 | 23 | 11 |
| 002 | tkp | 1300 | 544 | 133 | 11 | 11 |
| 009 | ckt | 1222 | 221 | 122 | 221 | 566 |
+--------+-------------+---------+-------------+----------------+------------+----------+
I have several invoice types. I want to show one particular CKT InvoiceType - Amount, OrderAmount, ShippingAmount, TruckTaxAmount in negative. I tried to multiply using when statement after where clause. But something is wrong.
You need to use the CASE WHEN in the SELECT clause, not after the WHERE clause:
SELECT
...
CASE WHEN InvoiceType='CKT' THEN Amount * -1.00 ELSE Amount END AS Amount,
CASE WHEN InvoiceType='CKT' THEN OrderAmount * -1.00 ELSE OrderAmount END AS OrderAmount,
(etc)
...
FROM ...
Thanks, #Tab Alleman
SELECT ... CASE WHEN InvoiceType='CKT' THEN Amount * -1.00 ELSE Amount END AS Amount,
CASE WHEN InvoiceType='CKT' THEN OrderAmount * -1.00 ELSE OrderAmount END AS
OrderAmount, (etc) ... FROM ... ------------------------------------------------------------------------
Related
In the below example the item code is split into 4 different lots (different versions of the same product)
the Item has 780 items allocated to orders across all lots. however the first lot only has 207 available i need another column to work out how many units are available using the oldest lot first eg the first lot in the example would be used up so would the 2nd and 3rd and there would be 382 units available from the final lot. im not too sure how to write this in sql. There are many more products in the dataset some with more and some with less lots.
Any Help would be apricated
Select
s.[Item Code]
,s.Lot
,s.[Allocated to Orders]
,s.[Available QOH]
from #StockValuation1 s
where s.[Item Code] = 'Test12080'
Desired outcome -
My solution utilises a window function to capture the running total as at the current allocation, which is then used to calculate the allocation per Lot and the remaining:
declare #t table(ItemCode int,Lot int,Allocated int, Available int);
insert into #t values
(1,1,780,207)
,(1,2,780,400)
,(1,3,780,55)
,(1,4,780,500)
,(1,5,780,100)
,(2,1,430,270)
,(2,2,430,140)
,(2,3,430,150)
,(2,4,430,50)
,(2,5,430,100)
;
with rt as
(
select ItemCode
,Lot
,Allocated
,Available
,case when rt >= Allocated
then Allocated - (rt - Available)
else rt - (rt - Available)
end as LotAllocation
from (select *
,sum(Available) over (partition by ItemCode order by Lot) as rt
from #t
) as t
)
select ItemCode
,Lot
,Allocated
,Available
,case when LotAllocation < 0
then 0
else LotAllocation
end as LotAllocation
,case when LotAllocation < 0
then Available
else Available - LotAllocation
end as AvailableLessAllocation
from rt
order by ItemCode
,Lot;
Output:
+----------+-----+-----------+-----------+---------------+-------------------------+
| ItemCode | Lot | Allocated | Available | LotAllocation | AvailableLessAllocation |
+----------+-----+-----------+-----------+---------------+-------------------------+
| 1 | 1 | 780 | 207 | 207 | 0 |
| 1 | 2 | 780 | 400 | 400 | 0 |
| 1 | 3 | 780 | 55 | 55 | 0 |
| 1 | 4 | 780 | 500 | 118 | 382 |
| 1 | 5 | 780 | 100 | 0 | 100 |
| 2 | 1 | 430 | 270 | 270 | 0 |
| 2 | 2 | 430 | 140 | 140 | 0 |
| 2 | 3 | 430 | 150 | 20 | 130 |
| 2 | 4 | 430 | 50 | 0 | 50 |
| 2 | 5 | 430 | 100 | 0 | 100 |
+----------+-----+-----------+-----------+---------------+-------------------------+
You can use cumulative sums. First get the amount allocated to the orders:
select s.*,
(case when allocated_to_orders >= running_qoh
then available_qoh
when allocated_to_orders <= running_qoh - available_qoh
then running_qoh - allocated_to_orders
else 0
end) as used_in_orders
from (select s.*,
sum(available_qoh) over (partition by item_code order by lot) as running_qoh
from #StockValuation1 s
) s
where s.[Item Code] = 'Test12080';
Then use a subquery or CTE to get the difference:
select s.*,
(available_qoh - used_in_orders) as available_for_orders
from (select s.*,
(case when allocated_to_orders >= running_qoh
then available_qoh
when allocated_to_orders <= running_qoh - available_qoh
then running_qoh - allocated_to_orders
else 0
end) as used_in_orders
from (select s.*,
sum(available_qoh) over (partition by item_code order by lot) as running_qoh
from #StockValuation1 s
) s
where s.[Item Code] = 'Test12080'
) s;
Note: I strongly recommend that you stop using spaces in your column names so you don't have escape them. The escape characters just make queries harder to write, read, and maintain.
Following data is of mobile selling shop.find Top 5 customers and their Avg Spend and avg Qty by each year.Also find change of Percentage of in their spend.
In this ques i want to ask how to calculate the percentage of change in their spend.
IDMODEL| CUSTID | DATE | price |QTY
-------------------------------------------
114 | 10015 |2005-02-15 | 52.00 | 1
110 | 10027 |2005-10-23 | 84.00 | 1
110 | 10038 |2003-02-26 | 170.00 | 2
130 | 10044 |2009-05-25 | 500.00 | 1
107 | 10043 |2003-04-16 | 126.00 | 1
126 | 10022 |2003-11-03 | 169.00 | 1
111 | 10045 |2010-01-01 | 286.00 | 1
118 | 10012 |2007-04-21 | 149.00 | 1
128 | 10044 |2010-10-19 | 318.00 | 1
124 | 10003 |2010-10-03 | 435.00 | 1
117 | 10002 |2010-10-13 | 54.00 | 1
112 | 10049 |2003-05-20 | 18.00 | 1
129 | 10041 |2004-02-04 | 409.00 | 1
126 | 10048 |2010-10-22 | 173.00 | 1
112 | 10024 |2005-03-23 | 17.00 | 1
select top 5 [CUSTID] as CUST,
avg([Price]) as AVG_SPEND,
avg([Qty]) as AVG_QTY ,
year(date) as year
from [dbo].[FACT_TRANSACTIONS]
group by [CUSTID],year(date)
order by AVG_SPEND desc
The following query might help you with the percentage calculation:
CREATE TABLE #temp (IDMODEL INT,CUSTID INT,[DATE] DATE,price NUMERIC(20,2), QTY INT)
INSERT INTO #temp VALUES
(114,100,'2005-02-15',52.00,1),
(115,100,'2005-10-23',100.00,2),
(116,100,'2006-10-23',120.00,1),
(117,100,'2007-10-23',90.00,3),
(118,100,'2007-10-23',84.00,1),
(114,100,'2008-10-23',52.00,1),
(110,200,'2005-10-23',80.00,1),
(116,200,'2006-10-23',120.00,2),
(115,200,'2006-10-23',100.00,1)
SELECT CUSTID
,dt_Year AS [Year]
,avg_Price AS [Average Price]
,avg_Qty AS [Average Quantity]
,total_Spend AS [Total Spend]
,CASE WHEN Prev_Spend = 0 THEN NULL ELSE CONVERT(NUMERIC(25,0),((total_Spend-Prev_Spend)/Prev_Spend) * 100) END AS [% Change]
FROM (
SELECT CUSTID,YEAR([DATE]) AS dt_Year,AVG(Price) AS avg_Price,AVG(QTY) AS avg_Qty,SUM([Spend]) AS [total_Spend]
,LAG(SUM(T.[Spend]),1,0) OVER(PARTITION BY CUSTID ORDER BY (YEAR([DATE]))) [Prev_Spend]
,ROW_NUMBER() OVER (PARTITION BY CUSTID ORDER BY SUM([Spend]) DESC) RNO
FROM #temp
CROSS APPLY (VALUES(Price*Qty)) AS T([Spend])
GROUP BY CUSTID,YEAR([DATE]) ) A
WHERE RNO <= 5
ORDER BY CUSTID,[Year]
The result is as below,
CUSTID Year Average Price Average Quantity Total Spend % Change
100 2005 76.000000 1 252.00 NULL
100 2006 120.000000 1 120.00 -52
100 2007 87.000000 2 354.00 195
100 2008 52.000000 1 52.00 -85
200 2005 80.000000 1 80.00 NULL
200 2006 110.000000 1 340.00 325
Looking for help in converting this to SQL Server 2008 friendly as I just can't work it out. I've tried cross applies and inner joins (not saying I did them right) to no avail... Any suggestions?
What this essentially does is have a table of stock and a table of orders.
and combine the two to show me what to pick once the stock is taken away (see my previous question for more details More Details)
WITH ADVPICK
AS (SELECT 'A' AS PlaceA,
placeb,
CASE
WHEN picktime = '00:00' THEN '07:00'
ELSE ISNULL(picktime, '12:00')
END AS picktime,
Cast(product AS INT) AS product,
prd_description,
-qty AS Qty
FROM t_pick_orders
UNION ALL
SELECT 'A' AS PlaceA,
placeb,
'0',
Cast(code AS INT) AS product,
NULL,
stock
FROM t_pick_stock),
STOCK_POST_ORDER
AS (SELECT *,
Sum(qty)
OVER (
PARTITION BY placeb, product
ORDER BY picktime ROWS UNBOUNDED PRECEDING ) AS new_qty
FROM ADVPICK)
SELECT *,
CASE
WHEN new_qty > qty THEN new_qty
ELSE qty
END AS order_shortfall
FROM STOCK_POST_ORDER
WHERE new_qty < 0
ORDER BY placeb,
picktime,
product
Now the whole sum over partition by order by is SQL Server 2012+ however I have two servers that run on 2008 and so need it converted...
Expected Results:
+--------+--------+----------+---------+-----------+-------+---------+-----------------+
| PlaceA | PlaceB | Picktime | product | Prd_Descr | qty | new_qty | order_shortfall |
+--------+--------+----------+---------+-----------+-------+---------+-----------------+
| BW | AMES | 16:00 | 1356 | Product A | -1330 | -17 | -17 |
| BW | AMES | 16:00 | 17 | Product B | -48 | -42 | -42 |
| BW | AMES | 17:00 | 1356 | Product A | -840 | -857 | -840 |
| BW | AMES | 18:00 | 1356 | Product A | -770 | -1627 | -770 |
| BW | AMES | 18:00 | 17 | Product B | -528 | -570 | -528 |
| BW | AMES | 19:00 | 1356 | Product A | -700 | -2327 | -700 |
| BW | AMES | 20:00 | 1356 | Product A | -910 | -3237 | -910 |
| BW | AMES | 20:00 | 8009 | Product C | -192 | -52 | -52 |
| BW | AMES | 20:00 | 897 | Product D | -90 | -10 | -10 |
+--------+--------+----------+---------+-----------+-------+---------+-----------------+
One straight-forward way to do it is to use a correlated sub-query in CROSS APPLY.
If your table is more or less large, then your next question would be how to make it fast. Index on PlaceB, Product, PickTime INCLUDE (Qty) should help. But, if your table is really large, cursor would be better.
WITH
ADVPICK
AS
(
SELECT 'A' as PlaceA,PlaceB, case when PickTime = '00:00' then '07:00' else isnull(picktime,'12:00') end as picktime, cast(Product as int) as product, Prd_Description, -Qty AS Qty FROM t_pick_orders
UNION ALL
SELECT 'A' as PlaceA,PlaceB, '0', cast(Code as int) as product, NULL, Stock FROM t_pick_stock
)
,stock_post_order
AS
(
SELECT
*
FROM
ADVPICK AS Main
CROSS APPLY
(
SELECT SUM(Sub.Qty) AS new_qty
FROM ADVPICK AS Sub
WHERE
Sub.PlaceB = Main.PlaceB
AND Sub.Product = Main.Product
AND T.PickTime <= Main.PickTime
) AS A
)
SELECT
*,
CASE WHEN new_qty > qty THEN new_qty ELSE qty END AS order_shortfall
FROM
stock_post_order
WHERE
new_qty < 0
ORDER BY PlaceB, picktime, product;
Oh, and if (PlaceB, Product, PickTime) is not unique, you'll get somewhat different results to original query with SUM() OVER. If you need exactly same results, you need to use some extra column (like ID) to resolve the ties.
i need to do one select with different where clauses (with different product code). The result which i need is below.
I have table like:
ApID | Date | Code | Qty | Price | Sum
222 | 2014-10-11 | 555 | 1 | 2,22 | 2,22
222 | 2014-10-11 | 555 | 1 | 2,22 | 2,22
222 | 2014-10-11 | 333 | 1 | 3,33 | 3,33
222 | 2014-10-12 | 555 | 1 | 2,22 | 2,22
My query:
SELECT
CAST(Date AS DATE) as 'Data',
SUM(Qty*Price) AS 'Sum',
SUM(Qty) AS 'Qty'
FROM Table
WHERE ApID = 222
AND Data BETWEEN '2014-10-11' AND '2014-10-13'
AND Code LIKE '555'
GROUP BY CAST(KvitoGalva.Data AS DATE)
I get result like this:
Data | Sum | Qty
2014-10-11 | 4.44 | 2
2014-10-12 | 2.22 | 1
I need to display result in one table:
Data | Sum 555 | Qty 555 | Sum 333 | Qty 333 |
2014-10-11 | 4.44 | 2 | 3.33 | 1 |
2014-10-12 | 2.22 | 1 | 0 | 0 |
Tried:
SELECT((Select1),(Select2))
----------------------------
SELECT 1
union
select 2
You can do this using conditional aggregation:
SELECT CAST(Date AS DATE) as Data,
SUM(case when code = '555' then Qty*Price else 0 end) AS Sum555,
SUM(case when code = '555' then Qty else 0 end) AS Qty555,
SUM(case when code = '333' then Qty*Price else 0 end) AS Sum333,
SUM(case when code = '333' then Qty else 0 end) AS Qty333
FROM Table t
WHERE ApID = 222 AND
Data BETWEEN '2014-10-11' AND '2014-10-13' AND
Code IN ('555', '333')
GROUP BY CAST(KvitoGalva.Data AS DATE);
Note: only use single quotes for string and date constants. You do not need quotes for column aliases and if you did, then your database would have a better character for escaping the names.
I have 2 tables: Income (InvoiceDate, TotalAmount) and Outcome (ExpenseDate, TotalAmount).
Suppose that I have data for each column as below:
Income:
| INVOICEDATE | TOTALAMOUNT |
|-------------|-------------|
| 2013-10-16 | 22000 |
| 2013-10-17 | 14400 |
| 2013-10-18 | 4488 |
Outcome:
| EXPENSEDATE | TOTALAMOUNT |
|-------------|-------------|
| 2013-10-25 | 15 |
I want to merge these 2 tables to show as below:
| DATE | INCOME | OUTCOME |
|------------|--------|---------|
| 2013-10-25 | 0 | 15 |
| 2013-10-16 | 22000 | 0 |
| 2013-10-17 | 14400 | 0 |
| 2013-10-18 | 4488 | 0 |
However when I run my T-SQL, It will show like this instead:
| DATE | INCOME | OUTCOME |
|------------|--------|---------|
| (null) | (null) | 15 |
| 2013-10-16 | 22000 | (null) |
| 2013-10-17 | 14400 | (null) |
| 2013-10-18 | 4488 | (null) |
This is my T-SQL:
SELECT
CASE (income.InvoiceDate)
WHEN NULL THEN Outcome.expenseDate
ELSE income.InvoiceDate
END AS [Date],
CASE (income.TotalAmount)
WHEN NULL THEN 0
ELSE income.TotalAmount
END AS Income,
CASE (Outcome.TotalAmount)
WHEN NULL THEN 0
ELSE Outcome.TotalAmount
END AS Outcome
FROM
Outcome
FULL OUTER JOIN
income ON Outcome.expenseDate = income.InvoiceDate
WHERE
NOT (
Outcome.TotalAmount = 0
AND income.TotalAmount = 0
)
You can test this SQL at http://sqlfiddle.com/#!6/3589f/1
Does anyone know what's wrong with my T-SQL?
Thank You!
Pengan
A CASE statement is a shorthand for a series of = operators. However, NULL is never equal to any value (that's what the IS operator is for), so using CASE to evaluate NULLs is somewhat pointless.
Instead, you can yse the COALESCE function to replace your NULLs with 0s as following:
SELECT Outcome.expenseDate AS [Date],
COALESCE(Income.TotalAMount, 0) AS Income,
COALESCE(Outcome.TotalAMount, 0) AS Outcome
FROM Outcome
FULL OUTER JOIN income ON Outcome.expenseDate = income.InvoiceDate
WHERE NOT (
Outcome.TotalAmount = 0
AND income.TotalAmount = 0
)
You may want a union instead
select InvoiceDate as Date, TotalAmount as Income, 0 as Outcome from Income
union all
select ExpenseDate, 0, TotalAmount from Outcome
If you can have income and expenses on the same date, you can group them from this.
select [date], Sum(Income), Sum(outcome) from
(
select InvoiceDate as Date, TotalAmount as Income, 0 as Outcome from Income
union all
select ExpenseDate, 0, TotalAmount from Outcome
) v
group by [date]
As to what is wrong with your statement, the problem is with the case.
They should use is null rather than when null
CASE WHEN income.TotalAmount IS NULL THEN 0 ELSE income.TotalAmount end,
But a shorter way is to use ISNULL
ISNULL(income.TotalAmount, 0)