How to Introduce new table - sql

I've 3 tables Tickets, Sales, Payments. Tickets and Payments have sale_id in it as a foreign key
Ticcekt Table Data
TicketID price service sale_id
1 19 City 1
2 19 City 1
3 15 St. Kilda 2
4 36 City 3
Sale table data
SaleID sale_time
1 2017-03-01
2 2017-03-01
3 2017-03-01
Payment table data
PaymentID amount sale_id payment_type
1 36 1 cash
2 15 2 eft
3 18 3 cash
4 18 3 eft
So Tickets and Payments table may have multiple records against 1 sale. If I have to right query to see the payment amount group by Ticket_table service column and I only have inner join option and also i can't write sub queries, than how i'll introduce a new table to make this work with a simple inner join query.
Currently if i do the inner join it returns me duplicate values. I'm doing this in Sisense where my only option is to introduce new tables to fix this.
So what would be the new table which comes in between and make this 1 to 1 relation
Edit
Desired result
Service payment_amount
City 72
St.kilda 15

Related

MS Access SQL, How to return only the newest row before a given date joined to a master table

I have two tables in a MS Access database as shown below. CustomerId is a primary key and fkCustomerId is a foreign key linked to the CustomerId in the other table.
Customer table
CustomerId
Name
1
John
2
Bob
3
David
Purchase table
fkCustomerId
OrderDate
fkStockId
1
01/02/2010
100
3
08/07/2010
101
2
14/01/2011
102
2
21/10/2011
103
3
02/03/2012
104
1
30/09/2012
105
3
01/01/2013
106
1
18/04/2014
107
3
22/11/2015
108
I am trying to return a list of customers showing the last fkStockId for each customer ordered before a given date.
So for the date 01/10/2012, I'd be looking for a return of
fkCustomerId
Name
fkStockId
1
John
105
2
Bob
103
3
David
104
A solution seems to be escaping me, any help would be greatly appreciated.
You can use nested select to get last order date.
SELECT Purchase.fkCustomerId,
Name,
fkStockId
FROM Purchase
JOIN
(
SELECT fkCustomerId,
MAX(OrderDate) as last_OrderDate
FROM Purchase
WHERE OrderDate < '01/10/2012'
GROUP BY fkCustomerId
) AS lastOrder
ON lastOrder.fkCustomerId = Purchase.fkCustomerId
AND last_OrderDate = OrderDate
LEFT JOIN Customer
ON Customer.CustomerId = Purchase.fkCustomerId
This example assumes OrderDate before '01/10/2012'. You might need to change it if you want it to be filtered by a different value.
Another assumption is that there's only one corresponding fkStockId for each OrderDate

Grouping and Summarize SQL

My table looks like the following:
income
date
productid
invoiceid
customerid
300
2015-01-01
A
1234551
1
300
2016-01-02
A
1234552
1
300
2016-01-03
B
1234553
2
300
2016-01-03
A
1234553
2
300
2016-01-04
C
1234554
3
300
2016-01-04
C
1234554
3
300
2016-01-08
A
1234556
3
300
2016-01-08
B
1234556
3
300
2016-01-11
C
1234557
3
I need to know : Number of invoices per customer, how many customers in total (for example one invoice = several customers, two invoices = two customers, three invoices = three customers, and so..).
What is the syntax for this query?
In my sample data above, customer 1 has two invoices, customer 2 one invoice and customer 3 three invoices. So there is one customer each with a count of 1, 2, and 3 invoices in my example.
Expected result:
invoice_count
customers_with_this_invoice_count
1
1
2
1
3
1
I tried this syntax and I'm still stuck:
select * from
(
select CustomerID,count(distinct InvoiceID) as 'Total Invoices'
from exam
GROUP BY CustomerID
) a
Select Count(customerID),CustomerID From a
Group By customerID
Having Count(customerID) > 1

New to SQL - How to compare data from two sets of joined tables

I'm trying to compare a set of multiple tables against another set of multiple tables in a SQL database. Admittedly, I'm very novice to SQL so please forgive me if my terminology is incorrect.
I have 6 individual tables in my database. 3 of those are comprised of current month's data and the other three are prior month's data. I need to produce a report that shows current month data, but also compare the account balance against the prior month - I need to create a column that will list "true" or "false" based on whether the account balances match.
I have joined the three current month's data tables together and I have joined the three prior month's data tables together.
The two sets of tables are identical. Below is a description of the tables - There is one set prefixed "CURRENT" and one prefixed "PRIOR":
BALANCE:
EntityID
AccountID
AccountBalance
ENTITY:
ID
Label
Description
ACCOUNT:
ID
AccountNumber
Description
The report I need to provide should list the following from the current month's data:
Label
Description
AccountNumber
AccountDescription
AccountBalance
I need to add a column called "Changed" at the end of the report. This column should have a "True" or "False" value depending on whether or not the current & prior account balances match.
Thus far, I have only been able to join the tables. I'm unsure how to edit this query to compare the current month dbo.CURRENT_BALANCE.AccountBalance against the prior month's dbo.PRIOR_BALANCE.AccountBalance
SELECT DISTINCT
dbo.CURRENT_ENTITY.Label,
dbo.CURRENT_ENTITY.Description AS Entity,
dbo.CURRENT_ACCOUNT.AccountNumber,
dbo.CURRENT_ACCOUNT.Description AS AccountDescription,
dbo.CURRENT_BALANCE.GLAccountBalance
FROM
dbo.CURRENT_BALANCE
INNER JOIN dbo.CURRENT_ENTITY ON dbo.CURRENT_BALANCE.EntityID = dbo.CURRENT_ENTITY.ID
INNER JOIN dbo.CURRENT_ACCOUNT ON dbo.CURRENT_BALANCE.AccountID = dbo.CURRENT_ACCOUNT.ID
CROSS JOIN dbo.PRIOR_BALANCE
INNER JOIN dbo.PRIOR_ENTITY ON dbo.PRIOR_BALANCE.EntityID = dbo.PRIOR_ENTITY.ID
INNER JOIN dbo.PRIOR_ACCOUNT ON dbo.PRIOR_BALANCE.AccountID = dbo.PRIOR_ACCOUNT.ID
The query above returns my expected results:
Label Entity AccountNumber AccountDescription AccountBalance
21 Company ABC 1 Customer Sales 25
21 Company ABC 2 Customer Sales 568
22 XYZ Solutions 3 Vendor Sales 344
23 Number 1 Products 4 Vendor Sales 565
24 Enterprise Inc 5 Wholesale 334
24 Enterprise Inc 6 Wholesale 5452
24 Enterprise Inc 7 Wholesale 5877
26 QWERTY Solutions 8 Customer Sales 456
27 Acme 9 Customer Sales 752
28 United Product Solutions 10 Vendor Sales 87
What I would like to do is have a result similar to:
Label Entity AccountNumber AccountDescription AccountBalance Changed
21 Company ABC 1 Customer Sales 25 FALSE
21 Company ABC 2 Customer Sales 568 FALSE
22 XYZ Solutions 3 Vendor Sales 344 FALSE
23 Number 1 Products 4 Vendor Sales 565 FALSE
24 Enterprise Inc 5 Wholesale 334 TRUE
24 Enterprise Inc 6 Wholesale 5452 FALSE
24 Enterprise Inc 7 Wholesale 5877 TRUE
26 QWERTY Solutions 8 Customer Sales 456 FALSE
27 Acme 9 Customer Sales 752 FALSE
28 United Product Solutions 10 Vendor Sales 87 FALSE
I have no idea where to go from here. Would appreciate any advise from this group!
The below should work as a way to compare the 2 values.
I have added aliases to table names to help with reading;
SELECT DISTINCT
ce.Label
,ce.Description AS Entity
,ca.AccountNumber
,ca.Description AS AccountDescription
,cb.GLAccountBalance
,CASE
WHEN cb.GLAccountBalance = p.PriorBalance THEN 'False'
WHEN cb.GLAccountBalance <> p.PriorBalance THEN 'True'
END AS [Changed]
FROM dbo.CURRENT_BALANCE cb
INNER JOIN dbo.CURRENT_ENTITY ce ON cb.EntityID = ce.ID
INNER JOIN dbo.CURRENT_ACCOUNT ca ON cb.AccountID = ca.ID
LEFT JOIN ( SELECT DISTINCT
pe.ID AS PE_ID
,pa.ID AS PA_ID
,pb.GLAccountBalance AS PriorBalance
FROM dbo.PRIOR_BALANCE pb
INNER JOIN dbo.PRIOR_ENTITY pe ON pb.EntityID = pe.ID
INNER JOIN dbo.PRIOR_ACCOUNT pa ON pb.AccountID = pa.ID
) p ON p.PE_ID = ce.ID AND p.PA_ID = ca.ID

Joining to another table only on the first occurrence of a field

Note: I have tried to simplify the below to make it simpler both for me and for anyone else to understand, the tables I reference below are in fact sub-queries joining a lot of different data together from different sources)
I have a table of purchased items:
Items
ItemSaleID CustomerID ItemCode
1 100 A
2 100 B
3 100 C
4 200 A
5 200 C
I also have transaction header and detail tables coming from a till system:
TranDetail
TranDetailID TranHeaderID ItemSaleID Cost
11 51 1 $10
12 51 2 $10
13 51 3 $10
14 52 4 $20
15 52 5 $10
TranHeader
TranHeaderID CustomerID Payment Time
51 100 $100 11:00
52 200 $50 12:00
53 100 $20 13:00
I want to get to a point where I have a table like:
ItemSaleID CustomerID ItemCode Cost Payment Time
1 100 A $10 $120 11:00
2 100 B $10 11:00
3 100 C $10 11:00
4 200 D $20 $50 12:00
5 200 E $10 12:00
I have a query which produces the results but when I add in the ROW_NUMBER() case statement goes from 2 minutes to 30+ minutes.
The query is further confused because I need to supply the earliest date relating to the list of transactions and the total price paid (could be many transactions throughout the day for upgrades etc)
Query below:
SELECT ItemSaleID
, CustomerID
, ItemCode
, Cost
, CASE WHEN ROW_NUMBER() OVER (PARTITION BY TranHeaderID ORDER BY ItemSaleID) = 1
THEN TRN.Payment ELSE NULL END AS Payment
FROM Items I
OUTER APPLY (
SELECT TOP 1 SUB.Payment, Time
FROM TranHeader H
INNER JOIN TranDetail D ON H.TranHeaderID = D.TranHeaderID
OUTER APPLY (SELECT SUM(Payment) AS Payment
FROM TranHeader H2
WHERE H2.CustomerID = Items.CustomerID
) SUB
WHERE D.CustomerID = I.CustomerID
) TRN
WHERE ...
Is there a way that I can only show payments for each occurrence of the customer ID whilst maintaining performance

SQL: How do I count the number of clients that have already bought the same product?

I have a table like the one below. It is a record of daily featured products and the customers that purchased them (similar to a daily deal site). A given client can only purchase a product one time per feature, but they may purchase the same product if it is featured multiple times.
FeatureID | ClientID | FeatureDate | ProductID
1 1002 2011-05-01 500
1 2333 2011-05-01 500
1 4458 2011-05-01 500
2 8888 2011-05-10 700
2 2333 2011-05-10 700
2 1111 2011-05-10 700
3 1002 2011-05-20 500
3 4444 2011-05-20 500
4 4444 2011-05-30 500
4 2333 2011-05-30 500
4 1002 2011-05-30 500
I want to count by FeatureID the number of clients that purchased FeatureID X AND who purchased the same productID during a previous feature.
For the table above the expected result would be:
FeatureID | CountofReturningClients
1 0
2 0
3 1
4 3
Ideally I would like to do this with SQL, but am also open to doing some manipulation in Excel/PowerPivot. Thanks!!
If you join your table to itself, you can find the data you're looking for. Be careful, because this query can take a long time if the table has a lot of data and is not indexed well.
SELECT t_current.FEATUREID, COUNT(DISTINCT t_prior.CLIENTID)
FROM table_name t_current
LEFT JOIN table_name t_prior
ON t_current.FEATUREDATE > t_prior.FEATUREDATE
AND t_current.CLIENTID = t_prior.CLIENTID
AND t_current.PRODUCTID = t_prior.PRODUCTID
GROUP BY t_current.FEATUREID
"Per feature, count the clients who match for any earlier Features with the same product"
SELECT
Curr.FeatureID
COUNT(DISTINCT Prev.ClientID) AS CountofReturningClients --edit thanks to feedback
FROM
MyTable Curr
LEFT JOIN
MyTable Prev WHERE Curr.FeatureID > Prev.FeatureID
AND Curr.ClientID = Prev.ClientID
AND Curr.ProductID = Prev.ProductID
GROUP BY
Curr.FeatureID
Assumptions: You have a table called Features that is:
FeatureID, FeatureDate, ProductID
If not then you could always create one on the fly with a temporary table, cte or view.
Then:
SELECT
FeatureID
, (
SELECT COUNT(DISTINCT ClientID) FROM Purchases WHERE Purchases.FeatureDate < Feature.FeatureDate AND Feature.ProductID = Purchases.ProductID
) as CountOfReturningClients
FROM Features
ORDER BY FeatureID
New to this, but wouldn't the following work?
SELECT FeatureID, (CASE WHEN COUNT(clientid) > 1 THEN COUNT(clientid) ELSE 0 END)
FROM table
GROUP BY featureID