mysql table inside join - sql

I have table tblsale.
In this table i have field called BillType, which contains "s" and "r" (s = sale , r = returns )
The table has rougly 25 records. Of that, 7 records are "r", and rest of the records are "s".
How do I write the query so that my result set includes the following columns:
What is want exactly is below
Amount BillType Amount BillType Date
100 s 50 r 29-11-2010
120 s 20 r 28-11-2010
130 s 30 r 27-11-2010
140 s 50 r 26-11-2010

What you appear to want are the results of two queries, sales and returns, side by side. It can be done with a kludge like this:
select amount, sale, returnamount, returned, returndate
from
(
select amount, 1 as sale, 0 as returnamount, 0 as returned, '' as returndate
from sales where billtype='s'
union
select 0 as amount, 0 as sale, amount as returnamount, 1 as returned, date as returndate
from sales where billtype ='r'
)
You may have to cast date into a string representation. The unioned sets need the same column structure, so you create dummy columns. (You didn't ask for a sale date for sales.)
Or you can do this with CASE WHEN statement.

I'm not sure what you are asking, but maybe:
SELECT BillNo, VAT, BillType, AfterDiscount FROM tblsale WHERE BillType = 's';

Related

Get count With Distinct in SQL Server

Select
Count(Distinct iif(t.HasReplyTask = 1, t.CustomerID, Null)) As Reply,
Count(Distinct iif(t.HasOverdueTask = 1, t.CustomerID, Null)) As Overdue,
Count(Distinct t.CustomerID) As Total
From
Table1 t
If a customer is in Reply, we need to remove that customer in Overdue count, That means if Customer 123 is in both, The Overdue count should be one less. How can I do this?
I am adding some data here,
Customer 123 has "HasReplyTask", so, we have to filter that customer from Count in OverDue(even though that customer has one Overdue task without HasReplyTask). 234 is one and Distinct of 456 is one.
So, the overdue count should be 2, Above query returns 3
If I've got it right, this can be done using a subquery to get the numbers for each customer, and then get the summary information as follows:
Select Sum(HasReplyTask) As Reply,
Sum(HasOverdueTask) As Overdue,
Count(CustomerID) As Total
From (
Select CustomerID,
IIF(Max(Cast(HasReplyTask As TinyInt))<>0, 0, Max(Cast(HasOverdueTask As TinyInt))) As HasOverdueTask,
Max(Cast(HasReplyTask As TinyInt)) As HasReplyTask
From Table1
Group by CustomerID) As T
I don't know about column data types, so I used cast function to use max function.
db<>fiddle
Reply
Overdue
Total
1
2
3
What would probably be more efficient for you is to pre-aggregate your table by customer ID and have counts per customer. Then your outer query can test for whatever you are really looking for. Something like
select
sum( case when PQ.ReplyCount > 0 then 1 else 0 end ) UniqReply,
sum( case when PQ.OverdueCount > 0 then 1 else 0 end ) UniqOverdue,
sum( case when PQ.OverdueCount - PQ.ReplyCount > 0 then 1 else 0 end ) PendingReplies,
count(*) as UniqCustomers
from
( select
yt.customerid,
count(*) CustRecs,
sum( case when yt.HasReplyTask = 1 then 1 else 0 end ) ReplyCount,
sum( case when yt.HasOverdueTask = 1 then 1 else 0 end ) OverdueCount
from
yourTable yt
group by
yt.customerid ) PQ
Now to differentiate the count you are REALLY looking for, you might need to do a test against the prequery (PQ) of ReplyCount vs OverdueCount such as... For a single customer ID (thus the pre query), if the OverdueCount is GREATER than the ReplyCount, then it is still considered overdue? So for customer 123, they had 3 overdue, but only 2 replies. You want that counted once? But for customers 234 and 456, the only had overdue entries and NO replies. So, the total where Overdue - Reply > 0 = 3 distinct people.
Is that your ultimate goal?

count based on store_A and all stores

I would like to count:
all count_products for store_A
the total count_products which includes all store_id's even store_A as total_count_products
Main_table
date store_id count_prroducts
2019-01-01 A 13
2019-01-01 B 34
2019-01-01 C 63
2019-01-01 D 10
Output_table
date store_A_count_products total_count_products
2019-01-0 13 120
Start out by selecting the date column without any modifications.
For store_A_count_products, basically what you need to do is add up all of the count_products whenever the store_id is A. You can do this with a case statement:
case when store_id = 'A' then count_products else 0 end
This is basically an IF/ELSE situation and will return a 0 for any row that doesn't have A in the store_id column.
If you wrap that up in a SUM(), you will add all the rows together.
For total_count_products, you just need to wrap a SUM() around count_products. This will add up all rows regardless of the status of any other column.
Finally, you need to group by the date column. The group by is a means to split the aggregated data across unaggregated columns.
The reason this works is because it gives you one row for each date, the summed total of products for Store A and the summed total of all products.
Select
date,
Sum(case when store_id = 'A' then count_products else 0 end) as store_A_count_products,
SUM(count_products) as total_count_products
From main_table
Group by date;

I need a support for sql query

I have a table with 3 columns lower range,upper range, discount amount
I am passing a number and finding in which range it belongs to and retrieving its discount amount
But i am passing a number that not in this table in this case i need the last range discount amount from table
I need a sql query for the same
0-10 100
11-20 200
21-30 300
if i am passing 5 need to get 100
if i am passing 15 200 as result
but if i am passing 50 i need to get 300 as result
Ie. If the value that is passing not in the range need to get the highest ranges discount amount.
Plzz help. Mee
Try this. You can directly pass/use #value in the script as well.
DECLARE #Value INT
SET #Value = 35
SELECT SUM(DISCOUNT) Discount
FROM
(
SELECT
CASE
WHEN upper_range = (SELECT MAX(upper_range) FROM your_table) AND #Value > upper_range THEN DISCOUNT
WHEN #Value BETWEEN lower_range AND upper_range THEN DISCOUNT
ELSE 0
END
DISCOUNT
FROM your_table
) A
Output for value 35 is-
300
With UNION ALL:
select discount
from tablename
where x between lowerrange and upperrange
union all
select max(discount) from tablename
where not exists (
select 1 from tablename
where x between lowerrange and upperrange
)
If the 1st query does not return a result, then the value will be fetched by the 2nd query.
If the 1st query returns a result, then the 2nd will not return anything.
Applies to any major rdbms.

SQL SUM and value conversion

I'm looking to transform data in my SUM query to acknowledge that some numeric values are negative in nature, although not represented as such.
I look for customer balance where the example dataset includes also credit transactions that are not written as negative in the database (although all records that have value C for credit in inv_type column should be treated as negative in the SQL SUM function). As an example:
INVOICES
inv_no inv_type cust_no value
1 D 25 10
2 D 35 30
3 C 25 5
4 D 25 50
5 C 35 2
My simple SUM function would not give me the correct answer:
select cust_no, sum(value) from INVOICES
group by cust_no
This query would obviously sum the balance of customer no 25 for 65 and no 35 for 32, although the anticipated answer would be 10-5+50 = 55 and 30 - 2 = 28
Should I perhaps utilize CAST function somehow? Unfortunately I'm not up to date on the underlying db engine, however good chance of it being of IBM origin. Most of the basic SQL code has worked out so far though.
You can use the case expression inside of a sum(). The simplest syntax would be:
select cust_no,
sum(case when inv_type = 'C' then - value else value end) as total
from invoices
group by cust_no;
Note that value could be a reserved word in your database, so you might need to escape the column name.
You should be able to write a projection (select) first to obtain a signed value column based on inv_type or whatever, and then do a sum over that.
Like this:
select cust_no, sum(value) from (
select cust_no
, case when inv_type='D' then [value] else -[value] end [value]
from INVOICES
) SUMS
group by cust_no
You can put an expression in the sum that calculates a negative value if the invoice is a credit:
select
cust_no,
sum
(
case inv_type
when 'C' then -[value]
else [value]
end
) as [Total]
from INVOICES

Calculate percentages of columns in Oracle SQL

I have three columns, all consisting of 1's and 0's. For each of these columns, how can I calculate the percentage of people (one person is one row/ id) who have a 1 in the first column and a 1 in the second or third column in oracle SQL?
For instance:
id marketing_campaign personal_campaign sales
1 1 0 0
2 1 1 0
1 0 1 1
4 0 0 1
So in this case, of all the people who were subjected to a marketing_campaign, 50 percent were subjected to a personal campaign as well, but zero percent is present in sales (no one bought anything).
Ultimately, I want to find out the order in which people get to the sales moment. Do they first go from marketing campaign to a personal campaign and then to sales, or do they buy anyway regardless of these channels.
This is a fictional example, so I realize that in this example there are many other ways to do this, but I hope anyone can help!
The outcome that I'm looking for is something like this:
percentage marketing_campaign/ personal campaign = 50 %
percentage marketing_campaign/sales = 0%
etc (for all the three column combinations)
Use count, sum and case expressions, together with basic arithmetic operators +,/,*
COUNT(*) gives a total count of people in the table
SUM(column) gives a sum of 1 in given column
case expressions make possible to implement more complex conditions
The common pattern is X / COUNT(*) * 100 which is used to calculate a percent of given value ( val / total * 100% )
An example:
SELECT
-- percentage of people that have 1 in marketing_campaign column
SUM( marketing_campaign ) / COUNT(*) * 100 As marketing_campaign_percent,
-- percentage of people that have 1 in sales column
SUM( sales ) / COUNT(*) * 100 As sales_percent,
-- complex condition:
-- percentage of people (one person is one row/ id) who have a 1
-- in the first column and a 1 in the second or third column
COUNT(
CASE WHEN marketing_campaign = 1
AND ( personal_campaign = 1 OR sales = 1 )
THEN 1 END
) / COUNT(*) * 100 As complex_condition_percent
FROM table;
You can get your percentages like this :
SELECT COUNT(*),
ROUND(100*(SUM(personal_campaign) / sum(count(*)) over ()),2) perc_personal_campaign,
ROUND(100*(SUM(sales) / sum(count(*)) over ()),2) perc_sales
FROM (
SELECT ID,
CASE
WHEN SUM(personal_campaign) > 0 THEN 1
ELSE 0
end AS personal_campaign,
CASE
WHEN SUM(sales) > 0 THEN 1
ELSE 0
end AS sales
FROM the_table
WHERE ID IN
(SELECT ID FROM the_table WHERE marketing_campaign = 1)
GROUP BY ID
)
I have a bit overcomplicated things because your data is still unclear to me. The subquery ensures that all duplicates are cleaned up and that you only have for each person a 1 or 0 in marketing_campaign and sales
About your second question :
Ultimately, I want to find out the order in which people get to the
sales moment. Do they first go from marketing campaign to a personal
campaign and then to sales, or do they buy anyway regardless of these
channels.
This is impossible to do in this state because you don't have in your table, either :
a unique row identifier that would keep the order in which the rows were inserted
a timestamp column that would tell when the rows were inserted.
Without this, the order of rows returned from your table will be unpredictable, or if you prefer, pure random.