Distinct on one column with multiple results - sql

I have a problem with my query through visual basic to access database. Lets say I have two tables as bellow.
+-------+-------------+-------------+------------+
| ID | Date1 | Date2 | CustomerID |
+-------+-------------+-------------+------------+
| 1 | 1-1-2013 | 1-1-2012 | 1 |
| 2 | 1-1-2013 | 1-1-2012 | 1 |
| 3 | 1-1-2013 | 1-1-2012 | 2 |
| 4 | 1-1-2013 | 1-1-2012 | 3 |
| 5 | 1-1-2013 | 1-1-2012 | 3 |
+-------+-------------+-------------+------------+
and
+----------+---------+
| ID | Name |
+----------+---------+
| 1 | John |
| 2 | Tina |
| 3 | Patrick |
+----------+---------+
I would like to get result with only unique numbers from Customer - ID in first table like this one bellow.
+----------+----------+-------------+------------+
| ID | Date1 | Date2 | CustomerID |
+----------+----------+-------------+------------+
| 1 | 1-1-2013 | 1-1-2012 | 1 |
| 3 | 1-1-2013 | 1-1-2012 | 2 |
| 4 | 1-1-2013 | 1-1-2012 | 3 |
+----------+----------+-------------+------------+
I've tried with this query but with no luck.
sqL = " SELECT DISTINCT Order.ID, Order.Date1, Order.Date2, Customer.Name
FROM Order (Order INNER JOIN Customer ON Order.CustomerID = Customer.ID)"
But the code does not give me the result I wanted. Can you please provide me some help with my query.

UPDATED This will do it
SELECT q.OrderID, o.Date1, o.Date2, o.CustomerID, c.Name AS CustomerName
FROM
(
(SELECT CustomerID, MIN(ID) AS OrderID
FROM [Order]
GROUP BY CustomerID
) AS q INNER JOIN [Order] AS o
ON q.OrderID = o.ID
) INNER JOIN Customer AS c
ON o.CustomerID = c.ID
Output:
OrderID | Date1 | Date2 | CustomerID | CustomerName
--------|----------|----------|------------|-------------
1 | 1/1/2013 | 1/1/2012 | 1 | John
3 | 1/1/2013 | 1/1/2013 | 2 | Tina
4 | 1/1/2013 | 1/1/2012 | 3 | Patrick
UPDATE: Based on your comments your real query might look like
SELECT q.ID, o.ID_narocila, o.datum_sprejema, o.rok_izdobave, o.status_artikla, o.status_narocila o.ID_stranke, c.naziv
FROM
(
(SELECT ID_stranke, MIN(ID) AS ID
FROM Narocilo
GROUP BY ID_stranke
) AS q INNER JOIN Narocilo AS o
ON q.ID = o.ID
) INNER JOIN Stranke AS c
ON o.ID_stranke = c.ID

From the desired result set you have shown, the following query will work:
SELECT Min(T2.ID) AS MinOfID, Min(T1.Date1) AS MinOfDate1, Min(T1.Date2) AS MinOfDate2, T1.CustomerID
FROM T2 INNER JOIN T1 ON T2.ID = T1.CustomerID
GROUP BY T1.CustomerID;

Related

Limit join with pagination

These are my db tables:
Users
| id | nme |
|----|------|
| 1 | Adam |
| 2 | Bob |
| 3 | Jan |
| 4 | Nico |
Products
| id | price |
|----|-------|
| 1 | 500 |
| 2 | 700 |
| 3 | 900 |
Orders
| id | user_id | product_id |
|----|---------|------------|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 7 | 3 | 1 |
| 8 | 3 | 2 |
| 9 | 3 | 3 |
| 10 | 4 | 3 |
I want to get up to 2 users, and their products bought. I came with this:
SELECT
users.id AS 'user_id', products.id AS 'product_id'
FROM
users
INNER JOIN
orders ON orders.user_id = users.id
INNER JOIN
products ON products.id = orders.product_id
ORDER BY
orders.id
OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY
But this returns:
| user_id | product_id |
|---------|------------|
| 1 | 1 |
| 1 | 2 |
What I want to get is up to 2 users, not orders. I want to get this:
| user_id | product_id |
|---------|------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
Any ideas?
I think you don't need a JOIN among tables but only using [Orders] table along with a window function such as DENSE_RANK() as seems the most suitable to filter out to return the result set such as
;WITH cte AS
(
SELECT *,
DENSE_RANK() OVER (ORDER BY [user_id]) AS rn
FROM [Orders]
)
SELECT [user_id], [product_id]
FROM cte
WHERE rn <= 2 -- returns only two user after sorted by their ids
ORDER BY 1, 2
Demo
You may use DENSE_RANK function with your join query as the following:
SELECT user_id, product_id
FROM
(
SELECT U.id AS 'user_id',
P.id AS 'product_id',
DENSE_RANK() OVER (ORDER BY U.id) dr
FROM users U INNER JOIN orders O
ON O.user_id = U.id
INNER JOIN products P
ON P.id = O.product_id
) T
WHERE dr between 1 and 2
ORDER BY user_id, product_id
WHERE dr between 1 and 2 allows you to perform pagination according to the order of user ids, i.e if you want to get users from 3 to 5, it will be WHERE dr between 3 and 5.
Check this demo.

How to fix query in order to display results?

I have multiple tables that i want to join in order to get the sum of a distinct column from all of them. My table structure example is as represented below.
Customers AS A
+---+-------+------------+--------+----------+
|id | name | profile_id | grp | end_date |
+---+-------+------------+--------+----------+
| 1 | cust1 | 7 | ae | (null) |
+---+-------+------------+--------+----------+
| 2 | cust2 | 2 | bz | (null) |
+---+-------+------------+--------+----------+
| 3 | cust2 | 2 | cc | not_null |
+---+-------+------------+--------+----------+
Profiles AS B
+---+-------------------+
|id | profile_name |
+---+-------------------+
| 2 | pro_cust1 |
+---+-------------------+
| 7 | pro_cust2 |
+---+-------------------+
Invoices AS C
+---+------------------+----------------+----------------+
|id | reference | scandate | customer_id |
+---+------------------+----------------+----------------+
| 1 | test_SOMETHING1 | (today) | 2 |
+---+------------------+----------------+----------------+
| 2 | test_2 | (today) | 2 |
+---+------------------+----------------+----------------+
| 3 | test_SOMETHING2 | (not_today) | 2 |
+---+------------------+----------------+----------------+
| 4 | test_SOMETHING3 | (today) | 1 |
+---+------------------+----------------+----------------+
| 5 | test_3 | (today) | 2 |
+---+------------------+----------------+----------------+
| 6 | test_SOMETHING4 | (not_today) | 1 |
+---+------------------+----------------+----------------+
Invoice_s_errors AS D
+---+------------------+----------------+----------------+
|id | reference | scandate | customer_id |
+---+------------------+----------------+----------------+
| 1 | tst_SOMETHING1 | (today) | 1 |
+---+------------------+----------------+----------------+
| 2 | tst_2 | (today) | 2 |
+---+------------------+----------------+----------------+
| 3 | tst_SOMETHING2 | (not_today) | 1 |
+---+------------------+----------------+----------------+
| 4 | tst_SOMETHING3 | (today) | 1 |
+---+------------------+----------------+----------------+
| 5 | tst_3 | (today) | 2 |
+---+------------------+----------------+----------------+
| 6 | tst_SOMETHING4 | (not_today) | 1 |
+---+------------------+----------------+----------------+
Invoice_fail AS E
+---+------------------+----------------+----------------+
|id | reference | scandate | customer_id |
+---+------------------+----------------+----------------+
| 1 | ttt_SOMETHING1 | (today) | 2 |
+---+------------------+----------------+----------------+
| 2 | ttt_2 | (today) | 1 |
+---+------------------+----------------+----------------+
| 3 | ttt_SOMETHING2 | (not_today) | 2 |
+---+------------------+----------------+----------------+
| 4 | ttt_SOMETHING3 | (today) | 2 |
+---+------------------+----------------+----------------+
| 5 | ttt_3 | (today) | 1 |
+---+------------------+----------------+----------------+
| 6 | ttt_SOMETHING4 | (not_today) | 2 |
+---+------------------+----------------+----------------+
Output:
+---------+---------------+--------+--------+
| customer+ profile | group | Total |
+---------+---------------+--------+--------+
| cust1 | pro_cust1 | ae | 2 |
+---------+---------------+--------+--------+
| cust2 | pro_cust2 | bz | 3 |
+---------+---------------+--------+--------+
Below is my code that's returning no data found . What am i doing wrong ?
SELECT
A.name as customer
,B.profile_name as profile
,A.grp as "Group"
,count(distinct C.reference) + count(distinct D.reference) + count(distinct E.reference) as "Total"
FROM
customers A
INNER JOIN
profiles B
ON
A.profile_id = B.id
INNER JOIN
invoices C
ON
A.id = C.customer_id
INNER JOIN
invoice_s_errors D
ON
A.id = D.customer_id
INNER JOIN
invoice_fail E
ON
A.id = E.customer_id
WHERE
A.end_date IS NULL
AND
(upper(C.reference) NOT LIKE ('%SOMETHING%') AND trunc(C.scandate) = trunc(sysdate))
AND
(upper(D.reference) NOT LIKE ('%SOMETHING%') AND trunc(D.scandate) = trunc(sysdate))
AND
(upper(E.reference) NOT LIKE ('%SOMETHING%') AND trunc(E.scandate) = trunc(sysdate))
GROUP BY A.name, A.grp, B.profile_name ORDER BY A.name ASC
It's your data, and because you INNER JOIN them.
The customerid's that have a "reference" without 'SOMETHING' are different in table alias E, compared to those in C & D
So change to LEFT JOIN's.
And then put some of the criteria that's now in the WHERE in the JOIN's.
Otherwise they would still act as INNER JOIN's.
SELECT
cust.name AS customer
,prof.profile_name AS profile
,cust.grp AS "Group"
,(COUNT(DISTINCT inv.reference) +
COUNT(DISTINCT inverr.reference) +
COUNT(DISTINCT invfail.reference)) AS "Total"
FROM customers cust
JOIN profiles prof ON prof.id = cust.profile_id
LEFT JOIN invoices inv
ON inv.customer_id = cust.id
AND upper(inv.reference) NOT LIKE ('%SOMETHING%')
AND trunc(inv.scandate) = trunc(sysdate)
LEFT JOIN invoice_s_errors inverr
ON inverr.customer_id = cust.id
AND upper(inverr.reference) NOT LIKE ('%SOMETHING%')
AND trunc(inverr.scandate) = trunc(sysdate)
LEFT JOIN invoice_fail invfail
ON invfail.customer_id = cust.id
AND upper(invfail.reference) NOT LIKE ('%SOMETHING%')
AND trunc(invfail.scandate) = trunc(sysdate)
WHERE cust.end_date IS NULL
GROUP BY cust.name, cust.grp, prof.profile_name
ORDER BY cust.name ASC

I can't get my desired SQL result

I have two tables:
Owners
+----+------+------------+
| id | name | birth_year |
+----+------+------------+
| 1 | John | 1970 |
| 2 | Jane | 1980 |
| 3 | Jack | 1990 |
| 4 | Josh | 2000 |
+----+------+------------+
Buylog
+----+----------+------------+
| id | owner_id | date |
+----+----------+------------+
| 1 | 1 | 01/01/2016 |
| 2 | 2 | 01/02/2016 |
| 3 | 2 | 01/03/2016 |
| 4 | 1 | 01/04/2016 |
+----+----------+------------+
I need to get all the info from Owners table plus the count of buys per owner:
+-----------+-------------+-------------------+--------------+
| owners.id | owners.name | owners.birth_year | buylog.Count |
+-----------+-------------+-------------------+--------------+
| 1 | John | 1970 | 2 |
| 2 | Jane | 1980 | 2 |
| 3 | Jack | 1990 | 0 |
| 4 | Josh | 2000 | 0 |
+-----------+-------------+-------------------+--------------+
I tried the below query, but that returns with error:
Select
o.id,
o.name,
o.birth_year,
Count(b.id) as Count
From
owners o
Left Outer Join
buylog b
On
b.owner_id = o.id
The error message should be pretty clear, you are missing a group by clause:
Select
o.id,
o.name,
o.birth_year,
Count(b.id) as Count
From
owners o
Left Outer Join
buylog b
On
b.owner_id = o.id
Group By o.id,
o.name,
o.birth_year
Query by HoneyBadger will do just fine, however this might perform better:
SELECT o.id
, o.name
, o.birth_year
, COALESCE(b.Count, 0) AS Count
FROM owners o
LEFT JOIN (
SELECT owner_id, COUNT(*) AS Count
FROM buylog
GROUP BY owner_id
) AS b
ON b.owner_id = o.id;
It should bring exactly the same result.
SELECT o.*,
CASE
WHEN temp.Buylog_count IS NULL THEN 0
ELSE temp.Buylog_count
END
FROM Owners o
LEFT JOIN
(
SELECT b.owner_id AS oid, COUNT(*) AS Buylog_count
FROM Buylog b
GROUP BY b.owner_id
)temp ON temp.oid = o.id

SQL Query to get results that match between three tables, or a single result for no match

Is there a way to use a where clause to check if there were zero matches between tables for a record from the first table, and produce one row or results reflecting that?
I'm trying to get results that look like this:
+----------+----------+-----------+----------+-------------+
| Results |
+----------+----------+-----------+----------+-------------+
| Date | Queue ID | From Date | To Date | Campaign ID |
| 3/1/2014 | 1 | 2/24/2014 | 3/2/2014 | 1 |
| 3/1/2014 | 2 | (NULL) | (NULL) | (NULL) |
+----------+----------+-----------+----------+-------------+
From a combination of tables that look like this:
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| Table 1 | | Table 2 | | Table 3 |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| Date | Queue | | Queue | SP | | SP | From Date | To Date | Campaign |
| | ID | | ID | ID | | ID | | | ID |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
| 3/1/2014 | 1 | | 1 | 1 | | 1 | 2/24/2014 | 3/2/2014 | 1 |
| 3/1/2014 | 2 | | 1 | 2 | | 2 | 3/3/2014 | 3/9/2014 | 5 |
| | | | 1 | 3 | | 3 | 3/10/2014 | 3/16/2014 | 1 |
| | | | 1 | 4 | | 4 | 3/17/2014 | 3/23/2014 | 1 |
| | | | 1 | 5 | | 5 | 3/24/2014 | 3/30/2014 | 4 |
| | | | 2 | 6 | | 6 | 3/3/2014 | 3/9/2014 | 5 |
| | | | 2 | 7 | | 7 | 3/10/2014 | 3/16/2014 | 5 |
| | | | 2 | 8 | | 8 | 3/17/2014 | 3/23/2014 | 5 |
| | | | 2 | 9 | | 9 | 3/24/2014 | 3/30/2014 | 5 |
+----------+-------+ +-------+----+ +----+-----------+-----------+----------+
I'm joining Table 1 to Table 2 on QUEUE ID,
and Table 2 to Table 3 on SP ID,
and DATE from Table 1 should fall between Table 3's FROM DATE and TO DATE.
I want a single record returned for each queue, including if there were no date matches.
Unfortunately any combinations of joins or where clauses I've tried so far only result in either one record for Queue ID 1 or multiple records for each Queue ID.
I would suggest this:
SELECT
t1.Date,
t1.QueueID,
s.FromDate,
s.ToDate,
s.CampaignID
FROM
Table1 t1
LEFT JOIN
(
SELECT
t2.QueueID,
t3.FromDate,
t3.ToDate,
t3.CampaignID
FROM
Table2 t2
INNER JOIN
Table3 t3 ON
t2.SPID = t3.SPID
) s ON
t1.QueueID = s.QueueID AND
t1.Date BETWEEN s.FromDate AND s.ToDate
SQL Fiddle here with an abbreviated dataset
A trivial amendment to AHiggins code. Using the CTE makes it a little easier to read perhaps.
With AllDates as
(
SELECT
t2.QueueID,
t3.FromDate,
t3.ToDate,
t3.CampaignID
FROM Table2 t2
INNER JOIN Table3 t3 ON
t2.SPID = t3.SPID
)
SELECT
t1.Date,
t1.QueueID,
s.FromDate,
s.ToDate,
s.CampaignID
FROM Table1 t1
LEFT JOIN AllDates s ON
t1.QueueID = s.QueueID AND
t1.Date BETWEEN s.FromDate AND s.ToDate
You want something like:
select distinct t1.date, t1,queue_id IFNULL(t3.from_date,'NULL'),
IFNULL(t3.to_date,'NULL'), IFNULL(t3.campaign,'NULL')
FROM table1 t1
LEFT OUTER JOIN table2 t2 on t1.queue_id = t2.queue_id
left outer join table3 t3 on t2.sp_id = t3.sp_id
where t3.from_date <= t1.date
AND t3.to_date >= t1.date
This will select dsitinct records from the table (eliminating null duplicates and replacing them with NULL)
SELECT t1.[Date], t1.[Queue ID], s.[From Date], s.[To Date], s.[Campaign ID]
FROM table1 t1
LEFT JOIN (SELECT t3.*, t2.[Queue ID] FROM table3 t3 JOIN table2 t2 ON t2.[SP ID] = t3.[SP ID]) s
ON s.[Queue ID] = t1.[Queue ID] AND t1.[Date] BETWEEN s.[From Date] AND s.[To Date]
SQL Fiddle

Generate report using SUM

I've got two SQL Server 2005 tables: MainTable and Orders.
MainTable:
| MainID | Serial |
-------------------
| 1 | A00001 |
| 2 | B00002 |
Orders:
| OrderID | MainID | Name | Value |
-----------------------------------
| 1 | 2 | John | 100 |
| 2 | 2 | Mike | 200 |
| 3 | 1 | John | 150 |
| 4 | 1 | Mike | 350 |
| 5 | 1 | John | 200 |
| 6 | 2 | John | 500 |
| 7 | 1 | Mike | 50 |
I want to get something like this:
|Serial | Name | Total |
-----------------------
| A00001 | John | 350 |
| A00002 | John | 600 |
| A00001 | Mike | 400 |
| A00002 | Mike | 200 |
SELECT
m.serial,
o.name,
SUM(o.value)
FROM
main m
INNER JOIN order o ON m.mainid = o.mainid
GROUP BY
o.name,
m.serial
select serial, name, sum(value) as total
from maintable m inner join orders o on
m.mainID = o.mainID
group by
serial, name
SELECT
M.SERIAL, O.NAME, SUM(VALUE) AS TOTAL
FROM MAINTABLE M JOIN ORDERS O ON O.MAINID=M.MAINID
GROUP BY M.SERIAL, O.NAME
select Serial , name , Total
from MainTable m,
( select MainID ,name, SUM(value) Total from Orders o group by MainID , Name ) O
where m.MainID= O.MainID