Get the right data for a specific id - sql

I want to get the prices for each product for a specific place. Here's what I have done so far.
SELECT pl.id AS place_id,
pl.data_name AS place_name,
pp.data_price AS product_price,
pp.date_updated AS price_updated
FROM places AS pl
JOIN products AS pr
ON pl.id = pr.id_place
JOIN products_prices AS pp
WHERE pp.id_product = '30'
GROUP BY pl.id, pp.data_price, pp.date_updated
ORDER BY pp.data_price DESC, pp.date_updated DESC
As you can see from the image above, product_price and price_updated are all the same. place_name also shows 3 places that does not have the product with id 30.
Here's how it should looks like (cheapest, most recent product purchase on top):
place_id place_name product_price price_updated
3 ICA Maxi 4.95 2018-05-16
1 ICA Supermarket 5.90 2018-05-27
26 ICA Skutan 6.50 2018-05-29
Here's the database structure:
CREATE TABLE IF NOT EXISTS `places` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`data_name` tinytext NOT NULL,
`data_address` text,
`data_address_city` tinytext NOT NULL,
`data_coordinates` varchar(50) NOT NULL,
UNIQUE KEY `id` (`id`)
);
INSERT INTO `places` (`id`, `data_name`, `data_address`, `data_address_city`, `data_coordinates`) VALUES
(1, 'ICA Supermarket', 'Björkhagsgatan 9', 'Skoghall', '59.324971,13.467291'),
(2, 'ICA Maxi', 'Bergviks Köpcentrum', 'Karlstad', '59.376563,13.428787'),
(3, 'ICA Kvantum', 'Bivägen 11', 'Hammarö', '59.343388,13.504583'),
(4, 'IKEA', 'Bergviksvägen 43', 'Karlstad', '59.379032,13.420646'),
(5, 'Karlstad Naprapatklinik', 'Västra Torggatan 15', 'Karlstad', '59.381379,13.501683'),
(9, 'Besök i Borgvik AB', '', 'Borgvik', '59.348261,12.954707'),
(23, 'Mariebergsskogen', '', 'Karlstad', '59.369403,13.486485'),
(24, 'Happy Price', 'Brehogsvägen 20', 'Tanumshede', '58.723730,11.344768'),
(25, 'Trekanten Kök & Bar', 'Parkvägen 2', 'Hamburgsund', '58.552733,11.270998'),
(26, 'ICA Skutan', 'Strandvägen', 'Hamburgsund', '58.552122,11.270898');
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_place` int(11) NOT NULL,
`data_barcode` text NOT NULL,
`data_name` text NOT NULL,
`data_weight` text NOT NULL,
`data_weight_type` text NOT NULL,
UNIQUE KEY `id` (`id`)
);
INSERT INTO `products` (`id`, `id_place`, `data_barcode`, `data_name`, `data_weight`, `data_weight_type`) VALUES
(7, 3, '7311070008494', 'Pågen Lantbröd', '650', 'g'),
(8, 3, '7310618084808', 'Grumme citronsåpa', '750', 'ml'),
(9, 3, '7318690079835', 'ICA Basic toalettpapper', '', ''),
(12, 1, '7318690134640', 'ICA Basic Milk & Caramel', '100', 'g'),
(18, 3, '7310380512103', 'ICA Home dishmatic refillsvamp', '', ''),
(19, 3, '7340109200684', 'Plastkasse', '', ''),
(20, 1, '7310751163903', 'ICA tonfisk filébitar i vatten', '185', 'g'),
(24, 1, '7310865001818', 'Arla mellanmjölk', '1.5', 'kg'),
(25, 1, '7318690079712', 'ICA kattsand (klumpbildande, ej parfym)', '6', 'kg'),
(29, 26, '3068320055008', 'Evian mineralvatten', '500', 'mL'),
(30, 26, '7318690134640', 'ICA Basic Milk & Caramel', '100', 'g'),
(33, 2, '0', 'ICA Basic Milk & Caramel', '100', 'g');
CREATE TABLE IF NOT EXISTS `products_prices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_product` int(11) NOT NULL,
`id_transaction` int(11) NOT NULL,
`data_price` decimal(10,2) NOT NULL,
`data_amount` tinytext NOT NULL,
`data_discount` tinytext,
`data_discount_amount` tinytext,
`data_discount_sum` tinytext,
`data_pant` tinytext,
`date_updated` date NOT NULL,
UNIQUE KEY `id` (`id`)
);
INSERT INTO `products_prices` (`id`, `id_product`, `id_transaction`, `data_price`, `data_amount`, `data_discount`, `data_discount_amount`, `data_discount_sum`, `data_pant`, `date_updated`) VALUES
(1, 1, 907, 18.90, '4', '', '2', '30', NULL, '2018-05-18'),
(2, 12, 907, 4.90, '4', '', '', '', NULL, '2018-05-18'),
(5, 4, 904, 18.90, '1', '', '', '', NULL, '2018-05-18'),
(6, 14, 904, 14.90, '1', '', '', '', NULL, '2018-05-18'),
(17, 19, 936, 2.00, '1', '', '', '', NULL, '2018-05-21'),
(18, 21, 947, 23.90, '1', '', '', '', NULL, '2018-05-23'),
(19, 22, 947, 10.50, '1', '', '', '', NULL, '2018-05-23'),
(20, 20, 947, 15.90, '1', '', '', '', NULL, '2018-05-23'),
(21, 13, 947, 49.90, '1', '', '', '', NULL, '2018-05-23'),
(22, 23, 948, 14.90, '1', '', '', '', NULL, '2018-05-24'),
(23, 24, 961, 14.90, '1', NULL, NULL, NULL, NULL, '2018-05-27'),
(24, 12, 961, 5.90, '4', NULL, NULL, NULL, NULL, '2018-05-27'),
(32, 28, 967, 8.50, '2', NULL, NULL, NULL, NULL, '2018-05-28'),
(33, 29, 972, 12.90, '1', NULL, NULL, NULL, '1', '2018-05-29'),
(34, 30, 973, 6.50, '2', NULL, NULL, NULL, NULL, '2018-05-29'),
(35, 31, 976, 10.00, '1', NULL, NULL, NULL, NULL, '2018-05-30'),
(36, 32, 976, 10.00, '1', NULL, NULL, NULL, NULL, '2018-05-30');

As mentioned in my comment to your request: You forgot the ON clause that links the products_prices table to the other two.
MariaDB nastily converts your inner join into a cross join instead of raising an error as it should. What this gives you is: select all prices for product 30 combined with all places multiplied with the number of products therein, instead of just combined with the product's place.
By the way: I'd put table products first in the FROM clause, because this is the base (you want product 30). Then join the product's prices and the product's place.
There is no reason to group your data, as you only want to list the prices. You are not aggregating anything. So you get:
SELECT
pl.id AS place_id,
pl.data_name AS place_name,
pp.data_price AS product_price,
pp.date_updated AS price_updated
FROM products AS pr
JOIN products_prices AS pp ON pp.id_product = pr.id
JOIN places pl ON pl.id = pr.id_place
WHERE pr.id = 30
ORDER BY pp.data_price DESC, pp.date_updated DESC;

Try this:
SELECT PL.id AS place_id,
PL.data_name AS place_name,
PP.data_price AS product_price,
PP.date_updated AS price_updated
FROM products_prices PP
JOIN products PR
ON PR.id = PP.id_product
JOIN places PL
ON PL.id = PR.id_place
WHERE PR.id = '30'

Related

Calculating distance then finding people within specific range of given latitude and longitude in SQL

I'm calculating distance between people like below:
select (
point(
(select latlng from user_account where name = 'Manel')
)
<#>
point(
(select latlng from user_account where name = 'Ben')
)
) as distance
which will then output like this:
The scenario is that if Manel wants to get all the people within 5 km, how to write the SQL Query?
(We are using name as the input parameter and there is Latlng stored in the table the type is point)
Here is the sample data:
DROP TABLE IF EXISTS "user_account";
DROP SEQUENCE IF EXISTS user_account_id_seq;
CREATE SEQUENCE user_account_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1;
CREATE TABLE "public"."user_account" (
"id" integer DEFAULT nextval('user_account_id_seq') NOT NULL,
"first_name" character varying(64) NOT NULL,
"last_name" character varying(64) NOT NULL,
"nickname" character varying(64),
"age" character varying(32),
"details" text,
"email" character varying(128),
"last_login_time" timestamp,
"create_time" timestamp,
"popularity" numeric(5,2),
"interested_in_relation" character varying(32),
"interested_in_gender" character varying(32),
"tag" character varying(256),
"point" integer,
"membership_type" character varying(32),
"account_status" character varying(32),
"account_name" character varying(32),
"password" character varying(32),
"latlng" point,
CONSTRAINT "user_account_ak_1" UNIQUE ("email"),
CONSTRAINT "user_account_pk" PRIMARY KEY ("id")
) WITH (oids = false);
INSERT INTO "user_account" ("id", "first_name", "last_name", "nickname", "age", "details", "email", "last_login_time", "create_time", "popularity", "interested_in_relation", "interested_in_gender", "tag", "point", "membership_type", "account_status", "account_name", "password", "latlng") VALUES
(8, 'Addison', 'Davies', 'Addison Davies', NULL, NULL, 'addison.davies#example.com', '2021-04-15 15:18:01.982', '2021-04-15 15:18:01.982', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'blackswan592', 'ajax', '(-0.1277,51.5073)'),
(10, 'Manel', 'Almeida', 'Manel Almeida', NULL, NULL, 'manel.almeida#example.com', '2021-04-15 15:28:25.85', '2021-04-15 15:28:25.85', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'orangekoala363', 'clarissa', '(-73.5959,-50.4127)'),
(11, 'Ben', 'Tidemann', 'Ben Tidemann', NULL, NULL, 'ben.tidemann#example.com', '2021-04-15 15:28:37.776', '2021-04-15 15:28:37.776', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'sadfrog539', 'morpheus', '(51.8397,-147.6034)'),
(12, 'Dieter', 'Campos', 'Dieter Campos', NULL, NULL, 'dieter.campos#example.com', '2021-04-15 15:28:38.939', '2021-04-15 15:28:38.939', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'silvercat262', 'irish', '(-72.8698,-139.8647)'),
(13, 'Girão', 'Martins', 'Girão Martins', NULL, NULL, 'girao.martins#example.com', '2021-04-15 15:33:58.464', '2021-04-15 15:33:58.464', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'yellowgoose254', 'shotgun', '(-69.7453,-170.808)'),
(14, 'Tammy', 'Hale', 'Tammy Hale', NULL, NULL, 'tammy.hale#example.com', '2021-04-15 15:33:59.925', '2021-04-15 15:33:59.925', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'beautifulzebra663', 'james007', '(25.8726,55.214)'),
(15, 'Hudson', 'Miller', 'Hudson Miller', NULL, NULL, 'hudson.miller#example.com', '2021-04-15 15:34:33.501', '2021-04-15 15:34:33.501', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'angrygorilla353', '414141', '(-59.3342,-90.5217)'),
(16, 'Apolline', 'Renard', 'Apolline Renard', NULL, NULL, 'apolline.renard#example.com', '2021-04-15 15:35:02.523', '2021-04-15 15:35:02.523', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'smallleopard612', '143143', '(0.6492,18.2443)'),
(17, 'Afet', 'Demirel', 'Afet Demirel', NULL, NULL, 'afet.demirel#example.com', '2021-04-15 15:35:08.072', '2021-04-15 15:35:08.072', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'happyfrog105', 'niners', '(75.6424,138.3762)'),
(18, 'Necati', 'Numanoğlu', 'Necati Numanoğlu', NULL, NULL, 'necati.numanoglu#example.com', '2021-04-15 15:35:09.242', '2021-04-15 15:35:09.242', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'bluefish441', 'beavis', '(70.8946,-7.5597)'),
(19, 'Danny', 'Soto', 'Danny Soto', NULL, NULL, 'danny.soto#example.com', '2021-04-15 15:35:10.32', '2021-04-15 15:35:10.32', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'blackpanda305', 'pentium', '(-79.9498,-171.0615)'),
(20, 'Jesse', 'Aro', 'Jesse Aro', NULL, NULL, 'jesse.aro#example.com', '2021-04-15 15:35:11.457', '2021-04-15 15:35:11.457', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'beautifulkoala522', 'lonely', '(-7.8552,-1.1386)'),
(21, 'Lucy', 'Zhang', 'Lucy Zhang', NULL, NULL, 'lucy.zhang#example.com', '2021-04-15 15:35:12.406', '2021-04-15 15:35:12.406', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'brownladybug716', 'beautiful', '(63.4473,52.2642)'),
(22, 'محیا', 'گلشن', 'محیا گلشن', NULL, NULL, 'mhy.glshn#example.com', '2021-04-15 15:35:13.503', '2021-04-15 15:35:13.503', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'browncat969', 'jorge', '(28.8925,109.2892)'),
(23, 'Jorge', 'Roman', 'Jorge Roman', NULL, NULL, 'jorge.roman#example.com', '2021-04-15 16:20:55.996', '2021-04-15 16:20:55.996', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'crazyostrich244', 'yyyyyyyy', '(-20.7278,-17.5191)'),
(24, 'Clayton', 'Jacobs', 'Clayton Jacobs', NULL, NULL, 'clayton.jacobs#example.com', '2021-04-15 16:20:57.276', '2021-04-15 16:20:57.276', NULL, NULL, NULL, NULL, 0, 'normal', 'active', 'happyrabbit978', 'killers', '(88.5666,-97.9353)');
Here is a query that returns all the people within a range of 5 km for a given name:
SELECT
ua1.id AS id1,
ua1.first_name AS name1,
ua1.latlng AS latlng1,
ua2.id AS id2,
ua2.first_name AS name2,
ua2.latlng AS latlng2,
(ua1.latlng <#> ua2.latlng) * 1.609344 as distance
FROM user_account ua1
JOIN user_account ua2 ON ua1.id <> ua2.id
WHERE ua1.first_name = 'Manel'
AND (ua1.latlng <#> ua2.latlng) * 1.609344 < 5;
Please note that the <#> operator returns miles instead of kilometers, so additional conversion is necessary, as shown above.
Thanks for Karol's nice answer! I also come up with a solution.
WITH latlng1 AS (
SELECT
latlng
FROM
user_account
WHERE
first_name = 'Manel'
),
result AS (
SELECT
(
point(
(latlng1.latlng)
) <#> point(
(user_account.latlng)
)
) as distance,
user_account.nickname
from
user_account,
latlng1
)
select
*
from
result
where
distance < 5 / 1.609344 AND nickname <> 'Manel Almeida'

How can I prevent SQL Server from squaring the number of rows scanned?

I'm running a query over a table variable that holds 22 227 rows. The query used to take 2-3 seconds to complete (which I still think is too slow) but since I added another field to the ORDER BY clause in DENSE_RANK() it now completes in 4.5 minutes!
If I include [t2].[aisdt] with or without [t2].[aiID], the execution plan shows that it's scanning 494 039 529 rows, which is 22 227 squared. The following query generates the correct results, just much too slowly to be useful.
SELECT MAX([t].[SetNum]) OVER (PARTITION BY NULL) AS [MaxSet]
,*
FROM (
SELECT DENSE_RANK() OVER (ORDER BY [t2].[aisdt], [t2].[aiID]) AS [SetNum]
,[t2].*
FROM (
SELECT [aiID]
,COUNT(DISTINCT [acID]) AS [noac]
FROM #Temp
GROUP BY [aiID]
) [t1]
JOIN #Temp [t2]
ON [t2].[aiID] = [t1].[aiID]
WHERE [t1].[noac] < [t2].[asm]
) [t]
Just to be clear, the culprit is the bold section in "DENSE_RANK() OVER (ORDER BY [t2].[aisdt], [t2].[aiID])". Removing this field (which needs to remain) drops the execution time back down to 2-3 seconds. I think it might have something to do with JOINing the table to itself on [aiID] but not [aisdt].
How can I speed this query up to complete in the same time as before, or less?
EDIT
Table definition:
DECLARE #Temp TABLE (
[aiID] INT NOT NULL INDEX [IX_Temp_aiID] -- not unique
,[aisdt] DATETIME NOT NULL INDEX [IX_Temp_aisdt] -- not unique
,[asm] INT NOT NULL
,[cpcID] INT NULL
,[cpce] VARCHAR(10) NULL
,[acID] INT NULL
,[ctvID] INT NULL
,[ct] VARCHAR(100) NULL
,[_36_other_non_matched_fields_] VARCHAR(MAX)
,UNIQUE ([aiID], [cpcID], [cpce], [acID], [ctvID], [ct])
)
[aisdt] is unique per [aiID], but there can be multiple [aiID]s with the same [aisdt].
INSERT INTO #TEMP
VALUES (64, '2017-03-23 10:00:00', 1, 17, '', NULL, NULL, NULL, 'blah')
,(64, '2017-03-23 10:00:00', 1, 34, '', NULL, NULL, NULL, 'blah')
,(99, '2017-04-08 09:00:00', 1, 25, 'Y', NULL, NULL, NULL, 'blah')
,(99, '2017-04-08 09:00:00', 1, 16, 'Y', NULL, NULL, NULL, 'blah')
,(99, '2017-04-08 09:00:00', 1, 76, 'Y', NULL, NULL, NULL, 'blah')
,(99, '2017-04-08 09:00:00', 1, 82, 'Y', NULL, NULL, NULL, 'blah')
,(42, '2017-04-14 16:00:00', 2, 32, '', 32, NULL, NULL, 'blah')
,(42, '2017-04-14 16:00:00', 2, 32, '', 47, NULL, NULL, 'blah')
,(42, '2017-04-14 16:00:00', 2, 47, '', 32, NULL, NULL, 'blah')
,(42, '2017-04-14 16:00:00', 2, 47, '', 47, NULL, NULL, 'blah')
,(54, '2017-03-23 10:00:00', 1, 17, '', NULL, NULL, NULL, 'blah')
,(54, '2017-03-23 10:00:00', 1, 34, '', NULL, NULL, NULL, 'blah')
,(89, '2017-04-08 09:00:00', 1, 25, 'Y', NULL, NULL, NULL, 'blah')
,(89, '2017-04-08 09:00:00', 1, 16, 'Y', NULL, NULL, NULL, 'blah')
,(89, '2017-04-08 09:00:00', 1, 76, 'Y', NULL, NULL, NULL, 'blah')
,(89, '2017-04-08 09:00:00', 1, 82, 'Y', NULL, NULL, NULL, 'blah')
,(32, '2017-04-14 16:00:00', 3, 32, '', 32, NULL, NULL, 'blah')
,(32, '2017-04-14 16:00:00', 3, 32, '', 47, NULL, NULL, 'blah')
,(32, '2017-04-14 16:00:00', 3, 47, '', 32, NULL, NULL, 'blah')
,(32, '2017-04-14 16:00:00', 3, 47, '', 47, NULL, NULL, 'blah')
It must be sorted by [aisdt] (datetime) first, then [aiID], then numbered into sets based on [aiID].
I want to see:
5, 1, 54, '2017-03-23 10:00:00', 1, 17, '', NULL, NULL, NULL, 'blah'
5, 1, 54, '2017-03-23 10:00:00', 1, 34, '', NULL, NULL, NULL, 'blah'
5, 2, 64, '2017-03-23 10:00:00', 1, 17, '', NULL, NULL, NULL, 'blah'
5, 2, 64, '2017-03-23 10:00:00', 1, 34, '', NULL, NULL, NULL, 'blah'
5, 3, 89, '2017-04-08 09:00:00', 1, 25, 'Y', NULL, NULL, NULL, 'blah'
5, 3, 89, '2017-04-08 09:00:00', 1, 16, 'Y', NULL, NULL, NULL, 'blah'
5, 3, 89, '2017-04-08 09:00:00', 1, 76, 'Y', NULL, NULL, NULL, 'blah'
5, 3, 89, '2017-04-08 09:00:00', 1, 82, 'Y', NULL, NULL, NULL, 'blah'
5, 4, 99, '2017-04-08 09:00:00', 1, 25, 'Y', NULL, NULL, NULL, 'blah'
5, 4, 99, '2017-04-08 09:00:00', 1, 16, 'Y', NULL, NULL, NULL, 'blah'
5, 4, 99, '2017-04-08 09:00:00', 1, 76, 'Y', NULL, NULL, NULL, 'blah'
5, 4, 99, '2017-04-08 09:00:00', 1, 82, 'Y', NULL, NULL, NULL, 'blah'
5, 5, 32, '2017-04-14 16:00:00', 3, 32, '', 32, NULL, NULL, 'blah'
5, 5, 32, '2017-04-14 16:00:00', 3, 32, '', 47, NULL, NULL, 'blah'
5, 5, 32, '2017-04-14 16:00:00', 3, 47, '', 32, NULL, NULL, 'blah'
5, 5, 32, '2017-04-14 16:00:00', 3, 47, '', 47, NULL, NULL, 'blah'
The main idea is taken from Partition Function COUNT() OVER possible using DISTINCT that #Jayvee pointed out with a small addition that would make it work when acID has NULL values.
Most likely you can remove all indexes from your #Temp table, the server will have to sort it in several different ways for different window functions anyway, but there is no self-join, so it should be faster.
The plan will have many sorts and they also can be slow, especially when engine underestimates the number of rows in a table. And table variable is exactly this case. Optimiser thinks that table variable has only 1 row. So, I'd recommend to use a classic #Temp table here, even without indexes.
An index on (aiID, acID) should help, but there will be other sorts any way.
WITH
CTE_Counts
AS
(
SELECT
*
-- use DENSE_RANK() to calculate COUNT(DISTINCT)
, DENSE_RANK() OVER (PARTITION BY [aiID] ORDER BY [acID])
+ DENSE_RANK() OVER (PARTITION BY [aiID] ORDER BY [acID] DESC)
-- subtract extra 1 if acID has NULL values within the partition
- MAX(CASE WHEN [acID] IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY [aiID])
- 1 AS [noac]
FROM #Temp
)
,CTE_SetNum
AS
(
SELECT
*
, DENSE_RANK() OVER (ORDER BY [aisdt], [aiID]) AS [SetNum]
FROM CTE_Counts
WHERE [noac] < [asm]
)
SELECT
*
, MAX([SetNum]) OVER () AS [MaxSet]
FROM CTE_SetNum
ORDER BY
[aisdt]
,[aiID]
,[SetNum]
;
Index as suggested in the comments would definitely play a major part but also I think you can re-write the query without self join in this way:
SELECT MAX([t].[SetNum]) OVER (PARTITION BY NULL) AS [MaxSet]
,*
FROM (
SELECT DENSE_RANK() OVER (ORDER BY [t1].[aisdt], [t1].[aiID]) AS [SetNum]
,[t1].*
FROM (
SELECT * ,dense_rank() over(partition by aiID order by [acID]) -
dense_rank() over(partition by aiID order by [acID]) - 1 AS [noac]
FROM #Temp
) [t1]
WHERE [t1].[noac] < [t1].[asm]
) [t]

SQL Query joining 5 tables

Trying to create a query to select all jobs that are unpaid and who the customer is for that job.
So the is required to first work out a calculation of what they owe (by a sum of s_partorders qty x price found in s_parts) and then minus what they have paid from s_payments.
This query joins it all together but I don't know how to group it by jobNumber because there can be multiple payments and multiple part orders.
SELECT a.jobNumber, a.customerID, a.quoteStatus, a.costDelivery, a.costCallout, a.costLabour, b.customerID, b.firstName, b.lastName, c.paymentID, c.jobNumber, c.amount, d.orderID, d.jobNumber, d.partID, d.quantity, e.partID, e.sellPrice
FROM s_jobcards a
INNER JOIN s_customers b ON a.customerID = b.customerID
INNER JOIN s_payments c ON a.jobNumber = c.jobNumber
INNER JOIN s_partOrders d ON a.jobNumber = d.jobNumber
INNER JOIN s_parts e ON d.partID = e.partID
WHERE a.quoteStatus = 0
Sorry it's quite messy and incomplete...
Included table structure and some test data.
CREATE TABLE IF NOT EXISTS `s_customers` (
`customerID` int(20) NOT NULL AUTO_INCREMENT,
`firstName` text NOT NULL,
`lastName` text NOT NULL,
`address` text NOT NULL,
`suburb` text NOT NULL,
`state` text NOT NULL,
`postcode` text NOT NULL,
`phone` text NOT NULL,
`altPhone` text NOT NULL,
`email` text NOT NULL,
`notes` text NOT NULL,
`postAddress` text NOT NULL,
`serviceDueDate` date NOT NULL,
PRIMARY KEY (`customerID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `s_customers` (`customerID`, `firstName`, `lastName`, `address`, `suburb`, `state`, `postcode`, `phone`, `altPhone`, `email`, `notes`, `postAddress`, `serviceDueDate`) VALUES
(1, 'David', 'Davinci', '654 Fake Road', 'Canning Vale', 'WA', '6164', '9546446', '45645646', 'dave#website.com', 'This guy is a butt', 'Cockburn Central', '2014-12-24'),
(2, 'Timmy', 'Trumpet', '69 something Street', 'Cockburn Central', 'WA', '6164', '9456456', '92344643', 'timmy#trumpet.com', 'Timmah?', '45 Timmy Street', '0000-00-00'),
(3, 'Jerry', 'Tester', '', '', '', '', '', '', '', '', '', '0000-00-00');
CREATE TABLE IF NOT EXISTS `s_jobcards` (
`jobNumber` int(6) NOT NULL AUTO_INCREMENT,
`dateReceived` date NOT NULL,
`workRequired` text NOT NULL,
`workCompleted` text NOT NULL,
`dateCompleted` date NOT NULL,
`customerID` int(5) NOT NULL,
`serviceTime` int(5) NOT NULL,
`serviceTech` int(1) NOT NULL,
`workOutstanding` text NOT NULL,
`quoteStatus` tinyint(1) NOT NULL DEFAULT '1',
`costDelivery` double NOT NULL,
`costCallout` double NOT NULL,
`costLabour` double NOT NULL,
PRIMARY KEY (`jobNumber`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `s_jobcards` (`jobNumber`, `dateReceived`, `workRequired`, `workCompleted`, `dateCompleted`, `customerID`, `serviceTime`, `serviceTech`, `workOutstanding`, `quoteStatus`, `costDelivery`, `costCallout`, `costLabour`) VALUES
(1, '2013-11-18', 'Create new service software. Yeah! 4534', 'Not a whole lot yet.?', '0000-00-00', 1, 5, 2, 'Complete this software?', 0, 50, 90, 90),
(2, '2013-11-18', 'work required', 'work done!', '0000-00-00', 1, 1, 3, 'work outstanding', 0, 0, 0, 0),
(3, '2014-12-01', 'Work harder.23432432 gdf', 'Go go!', '2014-12-01', 2, 1, 3, '', 1, 0, 0, 0),
(4, '0000-00-00', 'Whack some moles.', '', '0000-00-00', 3, 0, 1, '', 1, 0, 0, 0),
(5, '0000-00-00', '', '', '0000-00-00', 1, 0, 0, '', 1, 0, 0, 0);
CREATE TABLE IF NOT EXISTS `s_partOrders` (
`orderID` int(11) NOT NULL AUTO_INCREMENT,
`jobNumber` int(11) NOT NULL,
`partID` int(11) NOT NULL,
`quantity` int(11) NOT NULL,
PRIMARY KEY (`orderID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `s_partOrders` (`orderID`, `jobNumber`, `partID`, `quantity`) VALUES
(2, 0, 1, 5),
(3, 1, 1, 2),
(4, 1, 1, 6);
CREATE TABLE IF NOT EXISTS `s_parts` (
`partID` int(10) NOT NULL AUTO_INCREMENT,
`partNumber` varchar(50) NOT NULL,
`partDescription` text NOT NULL,
`modelID` int(5) NOT NULL,
`buyPrice` double NOT NULL,
`sellPrice` double NOT NULL,
`notes` text NOT NULL,
PRIMARY KEY (`partID`),
UNIQUE KEY `partNumber` (`partNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
INSERT INTO `s_parts` (`partID`, `partNumber`, `partDescription`, `modelID`, `buyPrice`, `sellPrice`, `notes`) VALUES
(1, '3453453453', 'Test Part', 1, 10.02, 30.5, 'This is a test part.');
CREATE TABLE IF NOT EXISTS `s_payments` (
`paymentID` int(11) NOT NULL AUTO_INCREMENT,
`amount` double NOT NULL,
`type` text NOT NULL,
`jobNumber` int(11) NOT NULL,
`paymentDate` date NOT NULL,
PRIMARY KEY (`paymentID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `s_payments` (`paymentID`, `amount`, `type`, `jobNumber`, `paymentDate`) VALUES
(2, 200, 'Visa', 1, '2014-12-05'),
(3, 20, 'Visa', 1, '2014-12-05');
Use outer joins where there might be no matching records, and aggregating data to jobnumber before joining will assist in ensuring the numbers are accurate:
select
j.jobNumber, j.customerID, j.quoteStatus, j.costDelivery, j.costCallout, j.costLabour
, c.customerID, c.firstName, c.lastName
, p.parts_sellprice
, sum(jp.amount) as paid
from s_jobcards as j
inner join s_customers as c on j.customerID = c.customerID
left outer join s_payments as jp on j.jobNumber = jp.jobNumber
left outer join (
select
d.jobNumber, sum(d.quantity * e.sellPrice) parts_sellprice
from s_partOrders d
left outer join s_parts e ON d.partID = e.partID
group by
d.jobNumber
) as p on j.jobNumber = p.jobNumber
group by
j.jobNumber, j.customerID, j.quoteStatus, j.costDelivery, j.costCallout, j.costLabour
, c.customerID, c.firstName, c.lastName
;
nb: I have assumed the sell price is multiplied by quantity
see this sqlfiddle demo: http://sqlfiddle.com/#!2/96f4c/1
select
j.jobNumber, j.customerID, j.quoteStatus, j.costDelivery, j.costCallout, j.costLabour
, c.customerID, c.firstName, c.lastName
, p.parts_sellprice
, sum(jp.amount) as paid
, (j.costDelivery + j.costCallout + j.costLabour + p.parts_sellprice) as Total_Cost
, (j.costDelivery + j.costCallout + j.costLabour + p.parts_sellprice) - sum(jp.amount) as Amount_Outstanding
from s_jobcards as j
inner join s_customers as c on j.customerID = c.customerID
left outer join s_payments as jp on j.jobNumber = jp.jobNumber
left outer join (
select
d.jobNumber, sum(d.quantity * e.sellPrice) parts_sellprice
from s_partOrders d
left outer join s_parts e ON d.partID = e.partID
group by
d.jobNumber
) as p on j.jobNumber = p.jobNumber
group by
j.jobNumber, j.customerID, j.quoteStatus, j.costDelivery, j.costCallout, j.costLabour
, c.customerID, c.firstName, c.lastName
;

SQL Query same table inner join eliminate duplicate

I have this table :
CREATE TABLE [BGIA].[INTCOL004VA](
[ID] [int] NOT NULL,
[DATYEN] [varchar](18) NULL,
[ZZRIDN] [varchar](8) NULL,
[OQTIEF] [varchar](1) NULL,
[OQMONE] [varchar](3) NULL,
[ZZPONR] [varchar](3) NULL,
[ZZNBRE] [varchar](15) NULL,
[ZZPDSE] [varchar](22) NULL
);
INSERT INTO INTCOL004VA VALUES
('53671955', 'MC1141103006', '38565363', '1', '007', '010', '0', '0'),
('53671956', 'MC1141103006', '38565363', '0', NULL, '020', '0', '0'),
('53671957', 'MC1141103006', '38565363', '0', '007', '030', '1', '500'),
('53671958', 'VT1141103010', '38565421', '1', '007', '050', '0', '0'),
('53671959', 'VT1141103010', '38565421', '0', NULL, '100', '0', '0'),
('53671960', 'ST1141103006', '38587542', '0', NULL, '010', '1', '500'),
('53671961', 'ST1141103006', '38587542', '1', 'B01', '020', '5', '0');
Records are linked by DATYEN, ZZRIDN and ZZPONR
I want update table with this rule :
For one link DATYEN, ZZRIDN if one row are not 0 on ZZNBRE and ZZPDSE => OQTIEF = 0 and OQMONE = NULL
But for one link DATYNE, ZZRIDN if all rows ar 0 on ZZNBRE and ZZPDSE and one row have OQTIEF = 1 and OQMONE not null => apply on all row af link OQTIEF = 1 and OQMONE = OQMONE of not null row
I can not do with an INNER JOIN and suddenly I do not know how to succeed
Thank you :)
Edit : For exemple, this :
('53671955', 'MC1141103006', '38565363', '1', '007', '010', '0', '0'),
('53671956', 'MC1141103006', '38565363', '0', NULL, '020', '0', '0'),
('53671957', 'MC1141103006', '38565363', '0', '007', '030', '1', '500')
Must be :
('53671955', 'MC1141103006', '38565363', '0', NULL, '010', '0', '0'),
('53671956', 'MC1141103006', '38565363', '0', NULL, '020', '0', '0'),
('53671957', 'MC1141103006', '38565363', '0', NULL, '030', '1', '500')
Because group MC1141103006 and 38565363 have one row with ZZNBRE and ZZPDSE not 0
This :
('53671960', 'ST1141103006', '38587542', '0', NULL, '010', '1', '500'),
('53671961', 'ST1141103006', '38587542', '1', 'B01', '020', '5', '0')
Must be :
('53671960', 'ST1141103006', '38587542', '0', NULL, '010', '1', '500'),
('53671961', 'ST1141103006', '38587542', '0', NULL, '020', '0', '0')
Because group ST1141103006 and 38587542 have one row with ZZNBRE and ZZPDSE not 0 but set ZZNBRE to 0 because ZZPDSE is 0
And this :
('53671958', 'VT1141103010', '38565421', '1', '007', '050', '0', '0'),
('53671959', 'VT1141103010', '38565421', '0', NULL, '100', '0', '0')
Must be :
('53671958', 'VT1141103010', '38565421', '1', '007', '050', '0', '0'),
('53671959', 'VT1141103010', '38565421', '1', '007', '100', '0', '0')
Because all row have ZZNBRE and ZZNBRE are 0
I hope to be precise, it is not easy to understand I guess :(
Edit 2 : Actually my query is :
update v1
set v1.zznbre = (case when v1.zzpdse = 0 then 0 else v1.zznbre end),
v1.oqtief = (case when v1.zznbre = 0 and v2.zznbre = 0 and v1.zzpdse = 0 and v2.zzpdse = 0 then 1 else 0 end),
v1.oqmone = (case when v1.zznbre = 0 and v2.zznbre = 0 and v1.zzpdse = 0 and v2.zzpdse = 0 then v2.oqmone else null end)
from intcol004va v1
inner join intcol004va v2 on v2.datyen = v1.datyen and v2.zzridn = v1.zzridn and v2.id <> v1.id
where v2.oqtief = 1 and v2.oqmone is not null and v1.oqtief <> v2.oqtief
But not work correctly in all case :(
If you process the update as two independent updates it appears to generate the correct answer set.
I included a result table and code that will show a comparison between original data and the desired result table as defined from your description.
Next it will do the two updates and then show the joined original and goal tables to demonstrate that they are aligned correctly.
CREATE TABLE [INTCOL004VA](
[ID] [int] NOT NULL,
[DATYEN] [varchar](18) NULL,
[ZZRIDN] [varchar](8) NULL,
[OQTIEF] [varchar](1) NULL,
[OQMONE] [varchar](3) NULL,
[ZZPONR] [varchar](3) NULL,
[ZZNBRE] [varchar](15) NULL,
[ZZPDSE] [varchar](22) NULL
);
CREATE TABLE [R_INTCOL004VA](
[ID] [int] NOT NULL,
[DATYEN] [varchar](18) NULL,
[ZZRIDN] [varchar](8) NULL,
[OQTIEF] [varchar](1) NULL,
[OQMONE] [varchar](3) NULL,
[ZZPONR] [varchar](3) NULL,
[ZZNBRE] [varchar](15) NULL,
[ZZPDSE] [varchar](22) NULL
);
INSERT INTO INTCOL004VA VALUES
('53671955', 'MC1141103006', '38565363', '1', '007', '010', '0', '0'),
('53671956', 'MC1141103006', '38565363', '0', NULL, '020', '0', '0'),
('53671957', 'MC1141103006', '38565363', '0', '007', '030', '1', '500'),
('53671958', 'VT1141103010', '38565421', '1', '007', '050', '0', '0'),
('53671959', 'VT1141103010', '38565421', '0', NULL, '100', '0', '0'),
('53671960', 'ST1141103006', '38587542', '0', NULL, '010', '1', '500'),
('53671961', 'ST1141103006', '38587542', '1', 'B01', '020', '5', '0');
INSERT INTO [R_INTCOL004VA] VALUES
('53671955', 'MC1141103006', '38565363', '0', NULL, '010', '0', '0'),
('53671956', 'MC1141103006', '38565363', '0', NULL, '020', '0', '0'),
('53671957', 'MC1141103006', '38565363', '0', NULL, '030', '1', '500'),
('53671960', 'ST1141103006', '38587542', '0', NULL, '010', '1', '500'),
('53671961', 'ST1141103006', '38587542', '0', NULL, '020', '0', '0'),
('53671958', 'VT1141103010', '38565421', '1', '007', '050', '0', '0'),
('53671959', 'VT1141103010', '38565421', '1', '007', '100', '0', '0')
SELECT
D.ID,
D.DATYEN,
D.ZZRIDN,
D.OQTIEF,
E.OQTIEF AS CORRECT_OQTIEF,
D.OQMONE,
E.OQMONE AS CORRECT_OQMONE,
D.ZZPONR,
D.ZZNBRE,
D.ZZPDSE
FROM
INTCOL004VA AS D
INNER JOIN
R_INTCOL004VA AS E ON D.ID = E.ID
UPDATE
INTCOL004VA
SET
OQTIEF = 0,
OQMONE = NULL
FROM
INTCOL004VA AS A
INNER JOIN
(SELECT
B.DATYEN,
B.ZZRIDN
FROM
INTCOL004VA AS B
GROUP BY
B.DATYEN,
B.ZZRIDN
HAVING
SUM(CAST(B.ZZNBRE AS INT)) > 0
) AS C ON A.DATYEN = C.DATYEN AND A.ZZRIDN = C.ZZRIDN
UPDATE
INTCOL004VA
SET
OQTIEF = 1,
OQMONE = C.OQMONE
FROM
INTCOL004VA AS A
INNER JOIN
(SELECT
B.DATYEN,
B.ZZRIDN,
MAX(ISNULL(B.OQMONE,'')) AS OQMONE
FROM
INTCOL004VA AS B
GROUP BY
B.DATYEN,
B.ZZRIDN
HAVING
SUM(CAST(B.OQTIEF AS INT)) > 0
) AS C ON A.DATYEN = C.DATYEN AND A.ZZRIDN = C.ZZRIDN
SELECT
D.ID,
D.DATYEN,
D.ZZRIDN,
D.OQTIEF,
E.OQTIEF AS CORRECT_OQTIEF,
D.OQMONE,
E.OQMONE AS CORRECT_OQMONE,
D.ZZPONR,
D.ZZNBRE,
D.ZZPDSE
FROM
INTCOL004VA AS D
INNER JOIN
R_INTCOL004VA AS E ON D.ID = E.ID
Sometimes just breaking it up into smaller pieces is the easier way to attack the problem.

How do I write this MySQL query to get the correct information? (Subquery, multiple subqueries)

Here is the query that I am working on:
SELECT `unitid`, `name` FROM apartmentunits
WHERE aptid = (
SELECT `aptid` FROM rentconditionsmap WHERE rentcondid = 1 AND condnum = 1
)
What I am having trouble figuring out is how to write this to add more rentcondition limiters to filter this list down more.
SELECT `aptid` FROM rentconditionsmap WHERE rentcondid = 1 AND condnum = 1
Data:
CREATE TABLE IF NOT EXISTS `rentconditionsmap` (
`rcid` bigint(10) unsigned NOT NULL AUTO_INCREMENT,
`rentcondid` int(3) unsigned NOT NULL,
`condnum` tinyint(3) unsigned NOT NULL,
`aptid` bigint(10) unsigned DEFAULT NULL,
PRIMARY KEY (`rcid`), KEY `aptid` (`aptid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=18 ;
INSERT INTO `rentconditionsmap`
(`rcid`, `rentcondid`, `condnum`, `aptid`)
VALUES
(1, 1, 1, 1),
(2, 2, 1, 1),
(3, 3, 0, 1),
(4, 4, 1, 1),
(5, 8, 0, 1);
CREATE TABLE IF NOT EXISTS `apartmentunits` (
`unitid` bigint(10) NOT NULL AUTO_INCREMENT,
`aptid` bigint(10) NOT NULL,
`name` varchar(6) NOT NULL,
`verified` tinyint(1) NOT NULL DEFAULT '0',
`rentcost` int(4) unsigned DEFAULT NULL,
`forrent` tinyint(1) NOT NULL DEFAULT '0',
`unittypekey` varchar(2) DEFAULT NULL,
`sqft` smallint(6) DEFAULT NULL,
PRIMARY KEY (`unitid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=121 ;
INSERT INTO `apartmentunits`
(`unitid`, `aptid`, `name`, `verified`, `rentcost`, `forrent`, `unittypekey`, `sqft`)
VALUES
(1, 1, '3', 1, 540, 0, '2B', NULL),
(2, 1, '5', 1, NULL, 0, '2B', NULL),
(3, 1, '7', 1, NULL, 0, '2B', NULL),
(53, 1, '1', 1, NULL, 0, '2B', NULL),
(54, 1, '2', 1, NULL, 0, '2B', NULL),
(55, 1, '4', 1, 570, 0, '2B', NULL),
(56, 1, '6', 1, NULL, 0, '2B', NULL),
(57, 1, '8', 1, NULL, 0, '2B', NULL),
(58, 1, '9', 1, NULL, 0, '2B', NULL),
(59, 1, '10', 1, NULL, 0, '2B', NULL),
(60, 1, '11', 1, NULL, 0, '2B', NULL);
As Eric J said as a comment:
Try changing = to IN
SELECT `unitid`, `name` FROM apartmentunits
WHERE `aptid` IN (
SELECT `aptid` FROM rentconditionsmap WHERE rentcondid = 1 AND condnum = 1
)
why not:
SELECT unitid, name
FROM apartmentunits a
INNER JOIN rentconditionsmap r on a.aptid = r.aptid
WHERE (rentcondid = 1 and condnum = 1) OR (rentcondid = 2 and condnum = 2)
Using ANSI-92 join syntax:
SELECT au.unitid,
au.name
FROM APARTMENTUNITS au
JOIN RENTCONDITIONSMAP rcm ON rcm.aptid = au.aptid
AND rcm.rentcondid = 1
AND rcm.condnum = 1
Use a JOIN (below is TSQL sintax for a join, or you can use the explicit INNER JOIN).
SELECT apartmentunits.unitid, apartmentunits.name
FROM apartmentunits, rentconditionsmap
WHERE apartmentunits.aptid = rentconditionsmap.aptid
AND rentconditionsmap.rentcondid = 1
AND rentconditionsmap.condnum = 1
-- AND whatever else...