SQL new column value based from another column in the same table - sql

I have a table with invoice sales lines and I am trying to make a query to generate a new column with the value from another column transaction in the same table. Already tried with CASE and subqueries, but the columns fills the value when meets the criteria:
The query is:
select [No_],
[Document No_],
Quantity,
[Line Discount _],
[Unit Price],
[new_column] = (select si.Quantity where CONVERT(decimal,si.[Unit Price]) = 0 )
from [Sales Invoice Lines] si
But what I really need is to have the new_column values in the transaction that the Unit Price is != 0.
What I am trying to accomplish is to get the Quantity values to the transactions that the Unit Price column has value and the No_ is the same:
Thanks.

The best solution is to go back in time and populate this column when generating the free sales line(s).
But now that that horse have left the barn, you can fetch them in a correlated subquery:
select ProductNO, Doc, Qty, Discount, Price
, CASE WHEN price > 0 THEN (select SUM(qty) FROM invoice_line il WHERE il.Doc= i.Doc AND il.Price = 0 AND il.ProductNO= i.ProductNO) END AS new_column
FROM invoice_line i
...
I'm guessing that production number of the free line should match the product number of the paid line, since you didn't bother mention it. This will also not work if multiple of the same paid products exist

Related

Different results in SQL based on what columns I display

I am trying to run a query to gather the total items on hand in our database. However it seems i'm getting incorrect data. I am selecting selecting just the amount field and summing it using joins from separate tables based on certain parameters, however if I display additional fields such as order number, and date all of a sudden im getting different data, even though those fields are being used as filters in the query. Is it because its not in the select statement? If it needs to be in the select statement is it possible to not display them?
Here are the two queries.
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt'
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
providing a sum of 21667457.20
and with the added columns
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt', [Requested Delivery Date], sh.No_, tw.[Status]
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
group by sh.[Requested Delivery Date], sh.No_, tw.[Status]
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
order by sh.[Requested Delivery Date] ASC
Providing a sum of 12319998
I'm self taught in SQL so I may be misunderstanding something obvious, thanks for the help.
With no sample data, I am going to have to demonstrate this in principle. In the latter query you have a GROUP BY meaning the scope of the values in the HAVING will differ, and thus the filtering from said HAVING will be different.
Let's take the following sample data:
CREATE TABLE dbo.MyTable (Grp char(1),
Quantity int,
Required int);
INSERT INTO dbo.MyTable (Grp, Quantity, [Required])
VALUES('a',2,7),
('a',14,2),
('b',4, 7),
('b',3,4),
('c',17,5);
Now we'll perform an overly simplified version of your query:
SELECT SUM(Quantity)
FROM dbo.MyTable
HAVING SUM(Quantity) > SUM(Required);
This brings back the value 40; which is the SUM of all the values in Quantity. A value is returned because the total SUM of Required is 25.
Now let's add a GROUP BY like your second query:
SELECT SUM(Quantity)
FROM dbo.MyTable
GROUP BY Grp
HAVING SUM(Quantity) > SUM(Required);
Now we have 2 rows, with the values 16 and 17 giving a total value of 33. That's because the rows where Grp have a value of 'B' are filtered out, as the SUM of Quantity is lower that Required for 'B'.
The same is happening in your data; in the grouped data you have groups where the HAVING condition isn't met, so those rows aren't returned.

SQL Pivot column values

I have tried following this and this(SQL Server specific solution) but were not helpful.
I have two tables, Product and Sale and I want to find how many products are sold on each day. But I want to pivot the table so that columns become the products name and each row will contain the amount of products sold for each day ordered by the day.
Simplified schema is as following
CREATE TABLE product (
id integer,
name varchar(40),
price float(2)
);
CREATE TABLE sale(
id integer,
product_id integer,
transaction_time timestamp
);
This is what I want
I only managed to aggregate the total sales per day per product but I am not able to pivot the product names.
select date(sale.transaction_date)
, product.id
, product.name
, count(product_id)
from sale inner join
product on sale.product_id = product.id
group by date(sale.transaction_date)
, product.id
, product.name
This is the situation so far
Please suggest.
You need pivoting logic, e.g.
select
s.transaction_date::date,
count(case when p.name = 'intelligent_rubber_clock' then 1 end) as intelligent_rubber_clock,
count(case when p.name = 'intelligent_iron_wallet' then 1 end) as intelligent_iron_wallet,
count(case when p.name = 'practical_marble_car' then 1 end) as practical_marble_car
from sale s
inner join product p
on s.product_id = p.id
group by
s.transaction_date::date;
Since your expected output aggregates by date alone, then only the transaction date should be in your GROUP BY clause. The trick used here is to take the count of a CASE expression which returns 1 when the record is from a given product, and 0 otherwise. This generates conditional counts for each product, all in separate columns. To add more columns, just add more conditional counts.

Retrieve the total number of orders made and the number of orders for which payment has been done

Retrieve the total number of orders made and the number of orders for which payment has been done(delivered).
TABLE ORDER
------------------------------------------------------
ORDERID QUOTATIONID STATUS
----------------------------------------------------
Q1001 Q1002 Delivered
O1002 Q1006 Ordered
O1003 Q1003 Delivered
O1004 Q1006 Delivered
O1005 Q1002 Delivered
O1006 Q1008 Delivered
O1007 Q1009 Ordered
O1008 Q1013 Ordered
Unable to get the total number of orderid i.e 8
select count(orderid) as "TOTALORDERSCOUNT",count(Status) as "PAIDORDERSCOUNT"
from orders
where status ='Delivered'
The expected output is
TOTALORDERDSCOUNT PAIDORDERSCOUNT
8 5
I think you want conditional aggregation:
select count(*) as TOTALORDERSCOUNT,
sum(case when status = 'Delivered' then 1 else 0 end) as PAIDORDERSCOUNT
from orders;
Try this-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
SUM(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE 0 END ) PAIDORDERSCOUNT
FROM ORDER
You can also use COUNT in place of SUM as below-
SELECT COUNT(ORDERID) TOTALORDERDSCOUNT,
COUNT(CASE WHEN STATUS = 'Delivered' THEN 1 ELSE NULL END ) PAIDORDERSCOUNT
FROM ORDER
you could use cross join between the two count
select count(orderid) as TOTALORDERSCOUNT, t.PAIDORDERSCOUNT
from orders
cross join (
select count(Status) PAIDORDERSCOUNT
from orders where Status ='Delivered'
) t
What I've used in the past for summarizing totals is
SELECT
count(*) 'Total Orders',
sum( iif( orders.STATUS = 'Delivered', 1, 0 ) ) 'Total Paid Orders'
FROM orders
I personally don't like using CASE WHEN if I don't have to. This logic may look like its a little too much for a simple summation of totals, but it allows for more conditions to be added quite easily and also just involves less typing, at least for what I use this regularly for.
Using the iif( statement to set up the conditional where you're looking for all rows in the STATUS column with the value 'Delivered', with this set up, if the status is 'Delivered', then it marks it stores a value of 1 for that order, and if the status is either 'Ordered' or any other value, including null values or if you ever need a criteria such as 'Pending', it would still give an accurate count.
Then, nesting this within the 'sum' function totals all of the 1's denoted from your matched values. I use this method regularly for report querying when there's a need for many conditions to be narrowed down to a summed value. This also opens up a lot of options in the case you need to join tables in your FROM statement.
Also just out of personal preference and depending on which SQL environment you're using this in, I tend to only use AS statements for renaming when absolutely necessary and instead just denote the column name with a single quoted string. Does the same thing, but that's just personal preference.
As stated before, this may seem like it's doing too much, but for me, good SQL allows for easy change to conditions without having to rewrite an entire query.
EDIT** I forgot to mention using count(*) only works if the orderid's are all unique values. Generally speaking for an orders table, orderid is an expected unique value, but just wanted to add that in as a side note.
SELECT DISTINCT COUNT(ORDERID) AS [TOTALORDERSCOUNT],
COUNT(CASE WHEN STATUS = 'ORDERED' THEN ORDERID ELSE NULL END) AS [PAIDORDERCOUNT]
FROM ORDERS
TotalOrdersCount will count all distinct values in orderID while the case statement on PaidOrderCount will filter out any that do not have the desired Status.

How to find net rows from sales and cancel rows using sql

I have a table with columns mentioned below:
transaction_type transaction_number amount
Sale 2016040433 50
Cancel R2016040433 -50
Sale 2016040434 50
Sale 2016040435 50
Cancel R2016040435 -50
Sale 2016040436 50
I want to find net number of rows with only sales which does not include canceled rows.
(Using SQL Only).
If you just want to count the sales and subtract the cancels (as suggested by your sample data), you can use conditional aggregation:
select sum(case when transaction_type = 'Sale' then 1
when transaction_type = 'Cancel' then -1
else 0
end)
from t;
SELECT count(transaction_type) FROM TBL_NAME GROUP BY count(transaction_type) HAVING transaction_type = 'Sale'
Just use the count function, and use HAVING with GROUP BY to filter
The list of row
select transaction_number, amount
from table
where transaction_type ='Sale';
or sum
select sum(amount)
from table
where transaction_type ='Sale';
or count
select count(*)
from table
where transaction_type ='Sale';
Since you have the transaction number, which i assume is a unique identifier for each transaction, i would use it to count the net sale rows.
Assuming then than every Cancelled transaction number is 'R'+ Sales transact number, then the query i propose is the following:
WITH CancelledSales_CTE (transaction_type, transaction_number, amount)
AS
(
SELECT transaction_type, RIGHT(transaction_number, LEN(transaction_number) - 1), amount
FROM Sales
WHERE transaction_type IS 'Cancel'
)
SELECT count(transaction_number)
FROM Sales
where transaction_number not in
(select distinct transaction_number from CancelledSales_CTE )
CancelledSales_CTE contains the list of cancelled rows, with the transaction number of the relative sale.
The count coming from
SELECT count(transaction_number)
FROM Sales
where transaction_number not in
(select distinct transaction_number from CancelledSales_CTE )
will exclude the transaction numbers which have been canceled

SQL Server: How to calculate different sums in a single query

A friend has suggested I post here as I'm in need of a bit of help!
DB Layout:
**salestable**
salesorder [primary, unique] (sales order number)
salesman (salesperson id)
**salesline**
salesorder [many sales line to single salestable relationship]
saleprice (line amount)
isaccessory (0 or 1)
I'd like to, in a single select, sum sales price as a total per salesman, but also sum sales price where is accessory = 1.
The grouping and joins aren't what I'm stuck on, it's whether I can do the dual sum.
In my head it would look something like
...salesman,sum(amount) as totalsales,sum(amount where accessory=1) as accessorysales...
But obviously that would never work!
Thanks in advance! (PS, I'm very new here, be gentle...)
SELECT salesman, SUM(amount), SUM(CASE WHEN accessory = 1 THEN amount ELSE 0 END)
FROM salestable t
JOIN salesorder o
ON o.salesorder = t.salesorder
GROUP BY
salesman