Query very slow with LEFT AND RIGHT JOIN - SQL Server CE - sql

I need to query the payment records with between date. The payment table has relation with invoice table while the invoice table has relation with customer table. So all the payment records must be shown even the invoice or the customer record already deleted.
To get less than 50 rows with 1 month period, it will take time more than 1 minutes. Any ideas how to reduce the times?
Here my snippet code :
SELECT
C.name, I.id as id, P.amount, P.date
FROM
tbl_customer C
LEFT JOIN
tbl_inv I ON C.id = I.id_customer
RIGHT JOIN
tbl_payment P ON I.id = P.id_invoice
WHERE
P.date >= '20131201' AND P.date <= '20140101'
ORDER BY
P.date;

Related

I need help to solve this exercise with SQL Server

I'm working with AdventureWorks Database. And this is the schema of the Database (https://i.stack.imgur.com/iWJxh.gif).
The exercise statement:
Do a report for the last week with following details.
OrderDate
Sales Person Name
SalesID
Customer Person Name
Quantity of products selled
Quantity of distinct products selled
Total Amount of the sale
Credit Card type used for pay
If sales had a special offer
Paying attention to the following statements:
Take the last 7 days for which you have sales data.
Do not show sales that were paid with cards of the type "ColonialVoice".
Dates should be displayed in "DD/MM/YYYY" format.
The report be ordered by Date, descending.
There should not be two rows with the same sale id in the report.
I try with this code and the results that it gives me are only for some dates, and if you pay attention it only brings me the first day of each month only
SELECT
SOH.OrderDate AS 'Fecha_Venta',
PERSONASVendedor.FirstName + ' ' + PERSONASVendedor.LastName AS 'Nombre_Vendedor',
SOH.SalesOrderID AS 'ID_Venta',
PERSONASCliente.FirstName + ' ' + PERSONASCliente.LastName AS 'Nombre_Cliente',
SUM(SOD.OrderQty) AS 'Cantidad_Productos_Vendidos',
COUNT(DISTINCT SOD.ProductID) AS 'Productos_Distintos_Vendidos',
SUM(SOD.LineTotal) AS 'Monto_Total',
TARJETA.CardType AS 'Tarjeta',
CASE WHEN SOD.SpecialOfferID <> 1 THEN 'Si' ELSE 'No' END AS 'Ventas_Con_Ofertas'
FROM Sales.SalesOrderHeader SOH
INNER JOIN Sales.SalesPerson ON SOH.SalesPersonID = Sales.SalesPerson.BusinessEntityID
INNER JOIN Sales.Customer ON SOH.CustomerID = Sales.Customer.CustomerID
INNER JOIN Person.Person PERSONASVendedor ON Sales.SalesPerson.BusinessEntityID = PERSONASVendedor.BusinessEntityID
INNER JOIN Person.Person PERSONASCliente ON Sales.Customer.PersonID = PERSONASCliente.BusinessEntityID
INNER JOIN Sales.SalesOrderDetail SOD ON SOH.SalesOrderID = SOD.SalesOrderID
INNER JOIN Sales.CreditCard TARJETA ON SOH.CreditCardID = TARJETA.CreditCardID
WHERE TARJETA.CardType <> 'ColonialVoice'
GROUP BY SOH.OrderDate, SOH.SalesOrderID, PERSONASVendedor.FirstName, PERSONASVendedor.LastName, PERSONASCliente.FirstName, PERSONASCliente.LastName, TARJETA.CardType, SOD.SpecialOfferID
ORDER BY SOH.OrderDate DESC
How can I solve this problem?
I would be missing to do some statements too.
Results obtained

How to see all data from one table and filtered on another, when using a join query (oracle sql)

Once I execute split, im hoping to see the following 3 things:
The customer record from CUSTOMERS
All customer transaction rows from TRANSACTIONS
Items purchased made during transactions 5 and 6 from PURCHASES
My query below gets most of this right except for point 2, as it only returns transactions 5 and 6 instead of the full list. What can I change?
SELECT * FROM customers c
INNER JOIN transactions t ON c.custid = t.custid
INNER JOIN purchaces p ON t.transid = p.transid
WHERE c.customer = 1234 AND t.trans_num IN (5,6)
ORDER BY t.trans_num
You are explicitely filtering for records 5 and 6 in your where statement. You can LEFT JOIN the purchases table using that condition. You will get all transactions, but the purchases columns will be NULL if they don't belong to transactions 5 or 6.
SELECT *
FROM customers c
INNER JOIN transactions t
ON c.custid = t.custid
LEFT JOIN purchaces p
ON t.transid = p.transid
AND t.trans_num IN (5,6)
WHERE c.customer = 1234
ORDER BY t.trans_num

Select Distinct in inner join with full customer record

I have two tables one with customer and another with invoices. I need to find all customer that have an more that one invoice with different days with in a period.
Invoice table:
Accountnum
Datein
IStatus
...
Customer table:
Accountnum
...
I have two problems:
1:
I can get the customers that have more than one invoice, but I don't know how to check if they are different days.
2:
Customer shows more than one time in this query they need to show only ones.
SELECT c.*
FROM Invoice I
INNER JOIN Customer C
ON I.Accountnum= C.Accountnum
WHERE EXISTS(SELECT DISTINCT I.AccountnumFROM Invoice
WHERE C.Accountnum = I.Accountnum
and i.Datein >= '2020-03-01' and i.Datein <= '2020-05-31'
and (IStatus <> 'V' or IStatus IS NULL)
GROUP BY I.Accountnum
HAVING COUNT(*) > 1)
A simple way to check if a given customer has invoices on two different dates is to ensure that the minimum invoice date differs from the maximum invoice date. You could write this as a join query:
select c.*
from customer c
inner join (
select accountnum
from invoice
where
datein >= '2020-03-01' and datein <= '2020-05-31'
and (istatus <> 'V' or istatus is null)
group by accountnum
having min(datein) <> max(datein)
) i on i.accountnum = c.accountnum
You are close, but no JOIN in the outer query:
SELECT c.*
FROM Customer C
WHERE (SELECT COUNT(*)
FROM Invoice
WHERE C.Accountnum = I.Accountnum AND
i.Datein >= '2020-03-01' and i.Datein <= '2020-05-31' AND
(IStatus <> 'V' or IStatus IS NULL)
) > 1;
Note that I also changed the logic of the subquery. The subquery returns a count which is then compared to 1, rather than using EXISTS.

left join two tables on a non-unique column in right table

I have two tables in sql server and i wanna select and join some data from these table.the first tables have some customer like:
---------------
customer id
Dave 1
Tom 2
---------------
and second table i table of purchases that includes list of last purchases with cost and which customer bought that Product:
------------------
product date customer id
PC 1-1-2000 1
phone 2-3-2000 2
laptop 3-1-2000 1
------------------
i wanna select first table (customers info) with last date of their purchases!
i tried left join but that doesn't give me last purchases becuase customer id is not unique in second table! how can i do this function with SQL server query? Regards
If you just want the max date, use aggregation. I would recommend a left join for customers who have made no purchases:
select c.customer, c.id, max(p.date)
from customers c left join
purchases p
on c.id = p.customer_id
group by c.customer, c.id;
Use the not exists clause for the win!
select c.customer, p.*
from Customer as c
inner join Purchase as p
on p.customer_id = c.id
where not exists (
select 1
from Purchase as p2
where p2.customer_id = p.customer_id
and p2.date > p.date
)
I think you can use inner join and group by
select table1.customer, table1.id, table.max(date)
from table1
inner join table2 on table1.id = table2.id
group by table1.customer, table1.id

Query two similar tables and combine sorted results

I have three tables
orders.orderid (and other non-pertinent stuff)
payment.orderid
payment.transactiondate
payment.amount
projectedpayment.orderid
projectedpayment.projecteddate
projectedpayment.projectedamount
Essentially, payment represents when actual payments are received; projectedpayment represents when the system thinks they should be received. I need to build a query to compare projected vs actual.
I'd like to query them such that each row in the query has the orderid, payment.transactiondate, payment.amount, projectedpayment.projecteddate, projectedpayment.projectedamount, with the rows from payment and projectedpayment sorted by their respective dates. e.g.,
orderid transactiondate amount projecteddate projectedamount
1 2015-01-01 12.34 2015-01-03 12.34
1 2015-01-15 12.34 2015-01-15 12.44
1 null null 2015-02-01 12.34
2 2014-12-31 50.00 null null
So broken down by order, what are the actual and projected payments, where there may be more projected payments than actual, or more actual payments than projected, aligned by date (simply by sorting the two, nothing more complex than that).
It seems like I should be able to achieve this with a left join from orders to some kind of union of the other two tables sorted with an order by, but I haven't been able to make it work, so it may be something completely different. I know I cannot join all three of order, payment, and projectedpayment or I get the cross-product of the latter two tables.
I happen to be using postgresql 9.4, but hopefully we don't need to get too database-specific.
I dont know postgres sorry :( but if you know how to do partitioned row numbers something like this should work.
select
coalesce(a.orderid,b.orderid) as orderid
,transactiondate
,amount
,projecteddate
,projectedamount
FROM
(select
orderid
,ransactiondate
,amount
,row_number() over (partition by orderid order by orderid,transactiondate) as rn
from payment) as a
full join
(select
orderid
,projecteddate
,projectedamount
,row_number() over (partition by orderid order by orderid,projecteddate) as rn
from projectedpayment) as b
on a.orderid= b.orderid
and a.rn = b.rn
*this is sqlserver syntax (2K5+ AFAIK)
The logic here is that you need to assign a unique number to each predicted and actual payment so that you can join the two tables together but only have each row matching a single row from the other table.
If you have ONLY ONE PAYMENT PER DAY then yo could do the full join on the order ID and date without worrying about row numbers.
the full join allows you to have nulls on either side so you will need to coalesce orderid
*also this doesn't show orders with NO payments or predictions.. comment if this is an issue.
This should work
Select * from Orders o
Left Join Payments p on o.ID = p.OrderID
Left Join ProjectedPaymentp pp on o.ID = pp.OrderID
Order By o.ID
If i correctly understand, the following query should help:
select o.orderid, ap.transactiondate, ap.amount, pp.projecteddate, pp.projectedamount
from orders o
left join
(
select p.orderid, p.transactiondate, p.amount,
row_number() over (partition by p.orderid order by p.transactiondate) n
from payment p
) ap on o.orderid = ap.order
left join
(
select p.orderid, p.projecteddate, p.projectedamount,
row_number() over (partition by p.orderid order by p.projecteddate) n
from projectedpayment p
) pp on o.orderid = ap.order and (ap.n is null or ap.n = pp.n)
order by o.orderid, ap.n, pp.n
UPD
Another option (works in slightly different way and you can have NULL values not only for last records for same orderid but it will be completely sorted by date, in one timeline):
select o.orderid, ap.transactiondate, ap.amount, pp.projecteddate, pp.projectedamount
from orders o
inner join
(
select ap.orderid, ap.transactiondate d from payment ap
union
select ap.orderid, ap.projecteddate d from projectedpayment pp
) d on d.orderid = o.orderid
left join payment ap on ap.orderid = o.orderid and ap.transactiondate = d.d
left join projectedpayment pp on pp.orderid = o.orderid and pp.projecteddate = d.d
order by o.orderid, d.d